﻿//
//--- History ------------------------------ 
// 2004/03/01 *** Releases version 2.0 ***
//------------------------------------------
// 2004/04/04 [ADD] Added method SetCssStyles(DWORD dwIdCssStyle, LPCTSTR lpszPathDll /* = NULL */)
// 2004/04/14 [FIX] Fixed correct drawing for some tooltip's directions
// 2004/04/15 [FIX] Fixed changing a z-order of the some windows by show a tooltip on Win9x
// 2004/04/27 [FIX] Corrected a work with a tooltip's directions with a large tooltip
// 2004/04/28 [ADD] Disables a message translation if object was't created (thanks to Stoil Todorov)
// 2004/07/02 [UPD] Changes a GetWndFromPoint mechanism of the window's searching
// 2004/09/01 [ADD] New SetMaxTipWidth method was added
// 2004/10/12 [FIX] Now a tooltip has a different methods to show a menu's tooltip and other 
//					control's tooltip
////////////////////////////////////////////////////////////////////
//
// "SmoothMaskImage" and "GetPartialSums" functions by Denis Sarazhinsky (c)2003
// Modified by Eugene Pustovoyt to use with image's mask instead of full color image.
//
/////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "PPTooltip.h"

// allow multi-monitor-aware code on Win95 systems
// comment out the first line if you already define it in another file
// comment out both lines if you don't care about Win95
//#define COMPILE_MULTIMON_STUBS
//#include "multimon.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define TIMER_HIDE		0x101 //the identifier of the timer for hide the tooltip
#define TIMER_SHOWING	0x102 //the identifier of the timer for tooltip's fade in
#define TIMER_SHOW		0x100 //the identifier of the timer for show the tooltip
#define TIMER_HIDING	0x103 //the identifier of the timer for tooltip's fade out
#define TIMER_ANIMATION 0x104 //the identifier of the timer for animation

#define PERCENT_STEP_FADEIN		20 //How mush percent will adding during fade in
#define PERCENT_STEP_FADEOUT	20 //How mush percent will adding during fade out
#define PERCENT_MAX_TRANSPARENCY 100 //How mush percent by maximum transparency
#define PERCENT_MIN_TRANSPARENCY 0 //How mush percent by minimum transparency

#define MAX_LENGTH_DEBUG_STRING 25 //

namespace CPPTooltip
{
	/*
	struct PPTOOLTIP_ENUM_CHILD 
	{
	HWND hwndExclude;
	HWND hWnd;
	POINT ptScreen;
	DWORD dwFlags;
	};

	BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam) 
	{ 
	PPTOOLTIP_ENUM_CHILD * structEnum = (PPTOOLTIP_ENUM_CHILD*)lParam;
	if (hwndChild != structEnum->hwndExclude)
	{
	DWORD dwStyle = ::GetWindowLong(hwndChild, GWL_STYLE);

	if (!(dwStyle & WS_VISIBLE))
	return TRUE;
	if (structEnum->dwFlags & CWP_SKIPDISABLED)
	{
	if (dwStyle & WS_DISABLED)
	return TRUE;
	}

	if ((dwStyle & 0xF) != BS_GROUPBOX)
	{
	RECT rcWindow;// = wi.rcWindow;
	::GetWindowRect(hwndChild, &rcWindow);

	if ((rcWindow.left <= structEnum->ptScreen.x) &&
	(rcWindow.right > structEnum->ptScreen.x) &&
	(rcWindow.top <= structEnum->ptScreen.y) &&
	(rcWindow.bottom > structEnum->ptScreen.y))
	{
	structEnum->hWnd = hwndChild;
	return FALSE;
	} //if 
	} //if
	} //if

	return TRUE;
	} //End EnumChildProc
	*/
	//////////////////
	// Note that windows are enumerated in top-down Z-order, so the menu
	// window should always be the first one found.
	//
	static BOOL CALLBACK MyEnumProc(HWND hwnd, LPARAM lParam)
	{
		TCHAR buf[16];
		GetClassName(hwnd, buf, sizeof(buf) / sizeof(TCHAR));
		if (_tcscmp(buf, _T("#32768")) == 0)  // special classname for menus
		{
			*((HWND*)lParam) = hwnd;	 // found it
			return FALSE;
		}
		return TRUE;
	}

	/////////////////////////////////////////////////////////////////////////////
	// CPPToolTip

	CPPToolTip::CPPToolTip()
	{
		// Default values
		m_dwTimeAutoPop = 5000;
		m_dwTimeInitial = 500;
		m_dwTimeFadeIn = 500;
		m_dwTimeFadeOut = 500;
		m_dwBehaviour = 0; //PPTOOLTIP_CLOSE_LEAVEWND | PPTOOLTIP_NOCLOSE_OVER;	 //The tooltip's behaviour
		m_dwEffectBk = 0;
		m_dwDirection = 0;
		m_dwStyles = 0;
		m_nGranularity = 0;
		m_nTransparency = 0;
		m_bDelayNextTool = FALSE;
		m_dwShowEffect = SHOWEFFECT_FADEINOUT;
		m_dwHideEffect = SHOWEFFECT_FADEINOUT;

		m_nTooltipState = PPTOOLTIP_STATE_HIDEN;
		m_nTooltipType = PPTOOLTIP_NORMAL;
		m_nNextTooltipType = PPTOOLTIP_NORMAL;

		m_ptOriginal.x = m_ptOriginal.y = 0;

		m_rcCurTool.SetRectEmpty();

		m_hwndDisplayedTool = NULL;

		m_hBitmapBk = NULL;
		m_hUnderTooltipBk = NULL;

		m_hbrBorder = NULL;
		m_hrgnTooltip = NULL;

		SetColorBk(::GetSysColor(COLOR_INFOBK));
		SetBorder(::GetSysColor(COLOR_INFOTEXT));
		EnableHyperlink();
		SetNotify(FALSE);
		SetDefaultSizes();
		SetDirection();
		SetBehaviour();
		SetDebugMode(FALSE);
		SetMaxTipWidth(0);
		//	EnableTextWrap(FALSE);
		SetDelayTime(PPTOOLTIP_TIME_INITIAL, 500);
		SetDelayTime(PPTOOLTIP_TIME_AUTOPOP, 5000);
		SetDelayTime(PPTOOLTIP_TIME_FADEIN, 0);
		SetDelayTime(PPTOOLTIP_TIME_FADEOUT, 0);
		SetTooltipShadow(6, 6);

#ifdef PPTOOLTIP_USE_MENU
		MenuToolPosition();
#endif //PPTOOLTIP_USE_MENU

		// Register the window class if it has not already been registered.
		WNDCLASS wndcls;
		HINSTANCE hInst = AfxGetInstanceHandle();
		if(!(::GetClassInfo(hInst, PPTOOLTIP_CLASSNAME, &wndcls)))
		{
			// otherwise we need to register a new class
			wndcls.style			= CS_SAVEBITS;
			wndcls.lpfnWndProc		= ::DefWindowProc;
			wndcls.cbClsExtra		= wndcls.cbWndExtra = 0;
			wndcls.hInstance		= hInst;
			wndcls.hIcon			= NULL;
			wndcls.hCursor			= LoadCursor(hInst, IDC_ARROW);
			wndcls.hbrBackground	= NULL;
			wndcls.lpszMenuName		= NULL;
			wndcls.lpszClassName	= PPTOOLTIP_CLASSNAME;

			if (!AfxRegisterClass(&wndcls))
				AfxThrowResourceException();
		} //if
	}

	CPPToolTip::~CPPToolTip()
	{
		FreeResources();
		RemoveAllTools();
		HideBorder();
	}


	BEGIN_MESSAGE_MAP(CPPToolTip, CWnd)
		//{{AFX_MSG_MAP(CPPToolTip)
		ON_WM_PAINT()
		ON_WM_TIMER()
		ON_WM_SETCURSOR()
		ON_WM_ACTIVATEAPP()
		//}}AFX_MSG_MAP
		ON_MESSAGE(UDM_TOOLTIP_REPAINT, OnRepaintWindow)
	END_MESSAGE_MAP()


	/////////////////////////////////////////////////////////////////////////////
	// CPPToolTip message handlers
	BOOL CPPToolTip::Create(CWnd* pParentWnd, BOOL bBalloon /* = TRUE */) 
	{
		TRACE(_T("CPPToolTip::Create\n"));

		ASSERT_VALID(pParentWnd);

		DWORD dwStyle = WS_POPUP; 
		DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
		m_hParentWnd = pParentWnd->GetSafeHwnd();

		if (!CreateEx(dwExStyle, PPTOOLTIP_CLASSNAME, NULL, dwStyle, 0, 0, 0, 0, pParentWnd->GetSafeHwnd(), NULL, NULL))
			return FALSE;

		//
		SetDefaultSizes(bBalloon);
		m_drawer.SetCallbackRepaint(this->GetSafeHwnd(), UDM_TOOLTIP_REPAINT);
		SetDelayTime(PPTOOLTIP_TIME_ANIMATION, 100);

		return TRUE;
	} //End of Create

	BOOL CPPToolTip::DestroyWindow() 
	{
		Pop();
		SetDelayTime(PPTOOLTIP_TIME_ANIMATION, 0);
		return CWnd::DestroyWindow();
	} //End of DestroyWindow

	/////////////////////////////////////////////////////////////////////
	//		A tooltip with PPTOOLTIP_DISABLE_AUTOPOP behaviour don't hide on 
	//	change active application
	//-------------------------------------------------------------------
	// Fixed by vanhoopy (July 10, 2003)
	/////////////////////////////////////////////////////////////////////
#if _MSC_VER < 1300
	void CPPToolTip::OnActivateApp(BOOL bActive, HTASK hTask)
#else
	void CPPToolTip::OnActivateApp(BOOL bActive, DWORD hTask)
#endif //_MSC_VER
	{
		CWnd::OnActivateApp(bActive, hTask);

		if (!bActive) 
			Pop();
	} //End of the WM_ACTIVATEAPP handler

	LRESULT CPPToolTip::SendNotify(LPPOINT pt, PPTOOLTIP_INFO & ti) 
	{ 
		TRACE(_T("CPPToolTip::SendNotify()\n")); 
		// Make sure this is a valid window  
		if (!IsWindow(GetSafeHwnd())) 
			return 0L; 
		// See if the user wants to be notified  
		if (!IsNotify()) 
			return 0L; 

		NM_PPTOOLTIP_DISPLAY lpnm; 
		lpnm.hwndTool = m_hwndNextTool;
		lpnm.pt = pt;  
		lpnm.ti = &ti; 
		lpnm.hdr.hwndFrom = m_hWnd; 
		lpnm.hdr.idFrom   = GetDlgCtrlID(); 
		lpnm.hdr.code     = UDM_TOOLTIP_DISPLAY; 

		::SendMessage(m_hNotifyWnd, WM_NOTIFY, lpnm.hdr.idFrom, (LPARAM)&lpnm);  

		return 0L;
	} //End of SendNotify

	/////////////////////////////////////////////////////////////////////
	// CPPToolTip::IsNotify()
	//		This function determines will be send the notification messages from 
	//	the control or not before display.
	//-------------------------------------------------------------------
	// Return value:
	//	TRUE if the control will be notified the specified window
	///////////////////////////////////////////////////////////////////////
	BOOL CPPToolTip::IsNotify()
	{
		TRACE(_T("CPPToolTip::IsNotify\n"));

		return (BOOL)(m_hNotifyWnd != NULL);
	}  //End of IsNotify

	BOOL CPPToolTip::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
	{
		CPoint ptClient;
		::GetCursorPos(&ptClient);
		ScreenToClient(&ptClient);
		TRACE (_T("CPPToolTip::OnSetCursor(x=%d, y=%d)\n"), ptClient.x, ptClient.y);
		if (m_drawer.OnSetCursor(&ptClient))
			return TRUE; //The cursor over the hyperlink

		::SetCursor(::LoadCursor(NULL, IDC_ARROW));

		//	return CWnd::OnSetCursor(pWnd, nHitTest, message);
		return TRUE;
	} //End of the WM_SETCURSOR handler

	LRESULT CPPToolTip::OnRepaintWindow(WPARAM wParam, LPARAM lParam)
	{
		TRACE (_T("CPPToolTip::OnRepaintWindow()\n"));
		if (m_bHyperlinkEnabled)
		{
			//Window's repaint enabled
			CDC * pDC = GetDC();
			OnRedrawTooltip(pDC->GetSafeHdc());
			ReleaseDC(pDC);
		}
		return TRUE;
	} //End of the UDM_TOOLTIP_REPAINT handler

	void CPPToolTip::OnDrawBorder(HDC hDC, HRGN hRgn)
	{
		ASSERT (hDC);
		ASSERT (hRgn);

		::FrameRgn(hDC, hRgn, m_hbrBorder, m_szBorder.cx, m_szBorder.cy);
	} //End OnDrawBorder

	////////////////////////////////////////////////////////////////////////
	//
	//      +-----------------+    +-------------------+   +-----------------+  
	//   +->|     Screen      +--->| m_hUnderTooltipBk |   |   m_hBitmapBk   |
	//   |  +--------+--------+    +-------------------+   +--------+--------+
	//   |           |                                            |
	//   |  +--------V--------+                          +--------V--------+
	//   |  |                 |     +--------------+     |                 |
	//   |  |                 |     |   DrawHTML   |---->|                 |
	//   |  |                 |     +--------------+     |                 |
	//   |  |                 |                          |     MemDC       |
	//   |  |                 |     +--------------+     |                 |
	//   |  |                 |     | OnDrawBorder |---->|                 |
	//   |  |     TempDC      |     +--------------+     +--------+--------+
	//   |  |                 |                                   |         
	//   |  |                 |     +--------------+              |         
	//   |  |                 |<----+  DrawShadow  |              |         
	//   |  |                 |     +--------------+              |         
	//   |  |                 |                                   |         
	//   |  |                 |<--------ALPHA---------------------+         
	//   |  |                 |
	//   |  +--------+--------+
	//   |           |          
	//   +-----------+
	//
	////////////////////////////////////////////////////////////////////////
	void CPPToolTip::OnRedrawTooltip(HDC hDC, BYTE nTransparency /* = 0 */)
	{
		TRACE (_T("CPPToolTip::OnRedrawTooltip(Transparency = %d)\n"), nTransparency);

		//ENG: If a transparency more then max value
		//RUS: 篷腓 珥圜屙桢 镳铉疣黜铖蜩 犷朦 爨犟桁嚯?漕矬耱桁钽?
		if (nTransparency > PERCENT_MAX_TRANSPARENCY)
			nTransparency = PERCENT_MAX_TRANSPARENCY;

		//ENG: If device context not passed
		//RUS: 篷腓 觐眚尻耱 篑蝠铋耱忄 礤 镥疱溧忄腭, 蝾 镱塍鬣屐 邈??篑蜞磬怆桠噱?镳桤磬?噔蝾爨蜩麇耜钽?箐嚯屙?
		BOOL bAutoReleaseDC = FALSE;
		if (NULL == hDC)
		{
			hDC = ::GetDC(this->GetSafeHwnd());
			bAutoReleaseDC = TRUE;
		} //if

		//ENG: Creates memory context
		//RUS: 杨玟噱?觐眚尻耱 篑蝠铋耱忄 ?镟?蜩
		HDC hMemDC = ::CreateCompatibleDC(hDC);
		HDC hBkDC = ::CreateCompatibleDC(hDC);
		HDC hTempDC = ::CreateCompatibleDC(hDC);
		HBITMAP hOldBkBitmap = (HBITMAP)::SelectObject(hBkDC, m_hBitmapBk);
		HBITMAP hBitmap = ::CreateCompatibleBitmap(hDC, m_rcBoundsTooltip.Width(), m_rcBoundsTooltip.Height());
		HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hMemDC, hBitmap);
		HBITMAP hTempBitmap = ::CreateCompatibleBitmap(hDC, m_rcBoundsTooltip.Width(), m_rcBoundsTooltip.Height());
		HBITMAP hOldTempBitmap = (HBITMAP)::SelectObject(hTempDC, hTempBitmap);

		//ENG: Gets the rectangle of the tooltip without a shadow
		//RUS: 项塍鬣屐 疣珈屦 蝮腧栾?徨?蝈龛
		CRect rect = m_rcBoundsTooltip;
		rect.DeflateRect(0, 0, m_szOffsetShadow.cx, m_szOffsetShadow.cy);

		//ENG: Copy background to the temporary bitmap
		//RUS: 暑镨痼屐 纛?镱?蝮腧栾铎 ?镟?螯
		::BitBlt(hMemDC, 0, 0, rect.Width(), rect.Height(),
			hBkDC, 0, 0, SRCCOPY);

		//ENG: Draw HTML string
		//RUS: 悟钺疣驵屐 HTML 耱痤牦
		m_drawer.DrawPreparedOutput(hMemDC, &m_rcTipArea);

		//ENG: Gets a region of a window
		//RUS: 项塍鬣屐 疱汨铐 铌磬
		//	HRGN hrgn = ::CreateRectRgn(0, 0, 0, 0);
		//	GetWindowRgn(hrgn);

		//ENG: Draw border of the tooltip
		//RUS: 悟钺疣驵屐 觐眚箴 蝮腧栾?
		if ((NULL != m_hbrBorder) && (m_szBorder.cx) && (m_szBorder.cy))
			OnDrawBorder(hMemDC, m_hrgnTooltip);

		if (NULL == m_hUnderTooltipBk)
		{
			//ENG: Stores a background under the tooltip to a bitmap
			//RUS: 杨躔囗屐 纛?镱?蝮腧栾铎 ?徼蜢囡
			m_hUnderTooltipBk = ::CreateCompatibleBitmap(hDC, m_rcBoundsTooltip.Width(), m_rcBoundsTooltip.Height());
			::SelectObject(hBkDC, m_hUnderTooltipBk);
			::BitBlt(hBkDC, 0, 0, m_rcBoundsTooltip.Width(), m_rcBoundsTooltip.Height(),
				hDC, m_rcBoundsTooltip.left, m_rcBoundsTooltip.top, SRCCOPY);
		}
		else
		{
			//ENG: Restores a background from a bitmap
			//RUS: 骂耨蜞磬怆桠噱?纛?桤 徼蜢囡?
			::SelectObject(hBkDC, m_hUnderTooltipBk);
		} //if

		//ENG: Copy a original background bitmap to the temporary DC
		//RUS: 暑镨痼屐 铕桡桧嚯 徼蜢囡 忸 怵屐屙睇?觐眚尻耱 镟?蜩
		::BitBlt(hTempDC, m_rcBoundsTooltip.left, m_rcBoundsTooltip.top, m_rcBoundsTooltip.Width(), m_rcBoundsTooltip.Height(),
			hBkDC, 0, 0, SRCCOPY);

		//ENG: Draws a shadow
		//RUS: 蔓忸滂?蝈睃
		if (m_szOffsetShadow.cx || m_szOffsetShadow.cy)
		{
			//ENG: Creates a mask of the tooltip for shadow
			//RUS: 杨玟噱?爨耜?蝮腧栾?潆 恹忸溧 蝈龛
			HBITMAP hMask = ::CreateCompatibleBitmap(hDC, rect.Width(), rect.Height());
			HDC hMaskDC = ::CreateCompatibleDC(hDC);
			//ENG: Creates a mask of the tooltip
			//RUS: 杨玟囗桢 爨耜?蝮腧栾?
			BYTE nColor = LOBYTE(::MulDiv(255, 100 - m_nDarkenShadow, 100));
			nColor += ((255 - nColor) * nTransparency) / 100;
			HBRUSH hBrush = ::CreateSolidBrush(RGB(nColor, nColor, nColor));
			HBITMAP hOldMask = (HBITMAP)::SelectObject(hMaskDC, hMask);
			::BitBlt(hMaskDC, 0, 0, rect.Width(), rect.Height(), NULL, 0, 0, WHITENESS);
			::FillRgn(hMaskDC, m_hrgnTooltip, hBrush);
			::DeleteObject(hBrush);
			::SelectObject(hMaskDC, hOldMask);
			::DeleteDC(hMaskDC);

			//HBITMAP hTempBmp = m_drawer.GetDrawManager()->CreateImageEffect(m_hTooltipMask, rect.Width(), rect.Height(), IMAGE_EFFECT_LIGHTEN, )
			m_drawer.GetDrawManager()->DrawShadow(hTempDC, 
				m_szOffsetShadow.cx, 
				m_szOffsetShadow.cy,
				rect.Width(), rect.Height(), hMask,
				m_bGradientShadow, 
				m_szDepthShadow.cx, m_szDepthShadow.cy);
			::DeleteObject(hMask);
		} //if

		//ENG: Merges a tooltip on with the client area 
		//RUS: 袜觌噤噱?蝮腧栾 磬 觌桢眚耜簋 鬣耱??嚯?磬腩驽龛屐
		::SelectClipRgn(hTempDC, m_hrgnTooltip);
		m_drawer.GetDrawManager()->AlphaBitBlt(hTempDC, m_rcBoundsTooltip.left, m_rcBoundsTooltip.top,
			rect.Width(), rect.Height(),
			hMemDC, 0, 0, 100 - nTransparency);
		::SelectClipRgn(hTempDC, NULL);

		//ENG: Output a tooltip to the screen
		//RUS: 蔓忸滂?蝮腧栾 磬 疣?
		::BitBlt(hDC, m_rcBoundsTooltip.left, m_rcBoundsTooltip.top,
			m_rcBoundsTooltip.Width(), m_rcBoundsTooltip.Height(),
			hTempDC, 0, 0, SRCCOPY);

		//ENG: Free resources
		//RUS: 务忸犷驿噱?玎溴轳蜮钼囗睇?疱耋瘃?
		::SelectObject(hBkDC, hOldBkBitmap);
		::SelectObject(hMemDC, hOldBitmap);
		::SelectObject(hTempDC, hOldTempBitmap);
		::DeleteObject(hBitmap);
		::DeleteObject(hTempBitmap);
		::DeleteDC(hBkDC);
		::DeleteDC(hMemDC);
		::DeleteDC(hTempDC);

		//ENG: Releases device context if needed
		//RUS: 务忸犷驿噱?觐眚尻耱 篑蝠铋耱忄 羼腓 ?礤钺躅滂祛
		if (bAutoReleaseDC)
			::ReleaseDC(this->GetSafeHwnd(), hDC);
	} //End of OnRedrawWindow

	void CPPToolTip::OnPaint() 
	{
		TRACE(_T("CPPToolTip::OnPaint()\n"));
		CPaintDC dc(this); // device context for painting

		//Copying info about current tool to displayed
		m_hwndDisplayedTool = m_hwndNextTool;
		m_tiDisplayed = m_tiNextTool;
		m_nTooltipType = m_nNextTooltipType;

		OnRedrawTooltip(dc.GetSafeHdc(), m_dwCurTransparency);
	} //End of the WM_PAINT handler

	BOOL CPPToolTip::PreTranslateMessage(MSG* pMsg) 
	{
		RelayEvent(pMsg);

		return CWnd::PreTranslateMessage(pMsg);
	}

	BOOL CPPToolTip::RelayEvent(MSG* pMsg)
	{
		//ENG: Disables a message translation if object was't created (thanks to Stoil Todorov)
		//RUS: 青镳弪 钺疣犷蜿?耦钺龛?羼腓 钺牝 礤 耦玟囗
		if (NULL == GetSafeHwnd())  
			return FALSE;

		ASSERT(m_hParentWnd);

		HWND hWnd = NULL;
		POINT pt;
		CRect rect;
		PPTOOLTIP_INFO ti;
		CString strTemp;

		switch(pMsg->message)
		{
		case WM_SETFOCUS:
			rect.left = 0;
			break;
		case WM_LBUTTONDOWN:
			TRACE(_T("CPPToolTip::WM_LBUTTONDOWN\n"));
			if (IsCursorOverTooltip())
			{
				//Left Button was pressed over the tooltip
				pt = pMsg->pt;
				ScreenToClient(&pt);
				m_drawer.OnLButtonDown(&pt); //
			} //if
		case WM_LBUTTONDBLCLK:
		case WM_RBUTTONDOWN:
		case WM_RBUTTONDBLCLK:
		case WM_MBUTTONDOWN:
		case WM_MBUTTONDBLCLK:
		case WM_NCLBUTTONDOWN:
		case WM_NCLBUTTONDBLCLK:
		case WM_NCRBUTTONDOWN:
		case WM_NCRBUTTONDBLCLK:
		case WM_NCMBUTTONDOWN:
		case WM_NCMBUTTONDBLCLK:
		case WM_KEYDOWN:
		case WM_SYSKEYDOWN:
		case WM_MOUSEWHEEL:
			//		// The user has interrupted the current tool - dismiss it
			//		if (!(m_tiDisplayed.nBehaviour & PPTOOLTIP_NOCLOSE_MOUSEDOWN))
			Pop();
			break;
		case WM_MOUSEMOVE:
			if ((PPTOOLTIP_HELP == m_nTooltipType) || (PPTOOLTIP_HELP == m_nNextTooltipType))
				return FALSE;
			if ((m_ptOriginal.x != pMsg->pt.x) || (m_ptOriginal.y != pMsg->pt.y))
			{
				// The mouse pointer's position was changed

				//Initialize values
				rect.SetRectEmpty();
				m_ptOriginal = pt = pMsg->pt;
				::ScreenToClient(m_hParentWnd, &pt);
				if (m_bDebugMode)
				{
					//Debug mode
					ti.sTooltip = GetDebugInfoTool(&pt);
					ti.nMask = 0;
					m_hwndDisplayedTool = NULL;
					SetNewTooltip(this->GetSafeHwnd(), ti);
				}
				else if (IsCursorOverTooltip() && !(m_tiDisplayed.nBehaviour & PPTOOLTIP_TRACKING_MOUSE)) 
				{
					//ENG: Mouse over a tooltip and tracking mode was disabled
					//RUS: 鼠瘃铕 磬?蝮腧栾铎 镳?恹觌屙眍?疱骅戾 "蝠嚓桧汔"
					if (!(m_tiDisplayed.nBehaviour & PPTOOLTIP_NOCLOSE_OVER))
					{
						//ENG: A tooltip don't hides when mouse over him
						//RUS: 篷腓 礤 篑蜞眍怆屙 耱桦?礤 玎牮囗? 蝮腧栾?羼腓 牦瘃铕 磬?龛?
						HideTooltip();
					}
					else
					{
						//ENG: Resetup autopop timer
						//RUS: 襄疱篑蜞磬怆桠噱?蜞殪屦 噔蝾玎牮? 蝮腧栾?
						SetAutoPopTimer();
					} //if
				}
				else
				{
					//ENG: Searching a toolbar's item
					//RUS: 腮屐 屐屙?磬 镟礤腓 桧耱痼戾眚钼
					hWnd = FindToolBarItem(pMsg->pt, ti);
					if (NULL == hWnd)
					{
						//ENG: Searching a hot area of the tooltip
						//RUS: 腮屐 镳邃铒疱溴脲眄簋 泐?黧?珙眢 蝮腧栾?
						hWnd = FindTool(&pt, ti);
					} //if
					TRACE ("吗屐屙眍?铌眍 = 0x%08X\n", hWnd);
					if (NULL == hWnd)
					{
						//ENG: An item with a tooltip wasn't found
						//RUS: 丸 钿桧 屐屙? 铗钺疣驵栝 蝮腧栾, 礤 磬殇屙
						m_hwndDisplayedTool = NULL;
						m_tiDisplayed.rectBounds.SetRectEmpty();
						KillTimer(TIMER_SHOW);
						HideTooltip();
					}
					else 
					{
						if ((hWnd != m_hwndDisplayedTool) || (ti.rectBounds != m_tiDisplayed.rectBounds/* m_rcDisplayedTool*/))
						{
							//ENG: Sets new tooltip for the new window or for the new window's item
							//RUS: 篷腓 眍忸?铌眍 桦?眍恹?屐屙?铌磬, 蝾 篑蜞眍忤螯 眍恹?蝮腧栾
							SetNewTooltip(hWnd, ti);
						}
						else
						{
							//ENG: Nothing was changed
							//RUS: 篷腓 龛 铌眍, 龛 屐屙?铌磬 礤 桤戾?腓顸
							if (m_tiDisplayed.nBehaviour & PPTOOLTIP_TRACKING_MOUSE)
							{
								//ENG: If sets tracking mode
								//RUS: 篷腓 篑蜞眍怆屙 疱骅?"蝠嚓桧汔"
								SetAutoPopTimer();
								OutputTooltipOnScreen(&pMsg->pt);
							}
							else if (!(m_tiDisplayed.nBehaviour & PPTOOLTIP_CLOSE_LEAVEWND))
							{
								//ENG: A tooltip must hide at anything mouse move
								//RUS: 篷腓 漕腈屙 镳蜞螯? 镳桦铎 溻桄屙梃 禧
								if ((hWnd == m_hwndDisplayedTool) && 
									!(m_tiDisplayed.nBehaviour & PPTOOLTIP_MULTIPLE_SHOW))
								{
									//ENG: "Multiple show" mode was disabled
									//RUS: 篷腓 礤 篑蜞眍怆屙 疱骅?祉铈羼蜮屙眍泐 镱赅玎 蝮腧栾?
									HideTooltip();
								}
								else
								{
									//ENG: "Multiple show" mode was enabled
									//RUS: 篷腓 篑蜞眍怆屙 疱骅?祉铈羼蜮屙眍泐 镱赅玎 蝮腧栾?
									SetNewTooltip(hWnd, ti);
								} //if
							}
							else
							{
								//ENG: A tooltip don't must when a mouse is over window
								//RUS: 殷腧栾 礤 漕腈屙 镳蜞螯? 镱赅 磬躅滂蝰 磬?铌眍?
								SetAutoPopTimer();
							} //if
						} //if
					} //if
				} //if
			} //if
			break;
		} //switch

		return FALSE;
	} //End RelayEvent

	void CPPToolTip::SetNewTooltip(HWND hWnd, const PPTOOLTIP_INFO & ti, BOOL bDisplayWithDelay /* = TRUE */, TooltipType type /* = PPTOOLTIP_NORMAL */)
	{
		TRACE (_T("CPPToolTip::SetNewTooltip(hWnd=0x%08X, CRect(left=%d, top=%d, right=%d, bottom=%d), nID=%d)\n"), 
			hWnd, ti.rectBounds.left, ti.rectBounds.top, ti.rectBounds.right, ti.rectBounds.bottom, ti.nIDTool);

		m_bNextToolExist = FALSE;

		//ENG: Hides a tooltip
		//RUS: 橡麇?蝮腧栾 羼腓 铐 镱赅玎?桦?镱赅琨忄弪?
		if ((PPTOOLTIP_STATE_SHOWING == m_nTooltipState) || 
			(PPTOOLTIP_STATE_SHOWN == m_nTooltipState))
			HideTooltip();

		//ENG: If a tooltip wasn't hidden
		//RUS: 篷腓 蝮腧栾 妁?礤 耧?蜞? 驿屐 ...
		m_nNextTooltipType = type;
		m_hwndNextTool = hWnd;
		m_tiNextTool = ti;
		if (PPTOOLTIP_STATE_HIDEN != m_nTooltipState)
		{
			TRACE(_T("SetNewTooltip2(%d)\n"), m_nNextTooltipType);
			m_bNextToolExist = TRUE;
			if (bDisplayWithDelay && m_dwTimeInitial)
				m_bDelayNextTool = TRUE;
			else 
				m_bDelayNextTool = FALSE;
			return;
		} //if

		//ENG: Start the show timer
		//RUS: 袜麒磬屐 镱赅?眍忸泐 蝮腧栾?
		if (bDisplayWithDelay && m_dwTimeInitial)
			SetTimer(TIMER_SHOW, m_dwTimeInitial, NULL);
		else
			OnTimer(TIMER_SHOW);
	} //End of SetNewTooltip

	void CPPToolTip::OnTimer(UINT nIDEvent) 
	{
		POINT pt;
		switch (nIDEvent)
		{
		case TIMER_SHOW:
			TRACE(_T("OnTimerShow(%d)\n"), m_nNextTooltipType);
			//ENG: Kill SHOW timer 
			//RUS: 俞栩?蜞殪屦 铈桎囗? 镱赅玎 蝮腧栾?
			KillTimer(TIMER_SHOW);
			//ENG: Get current mouse coordinates
			//RUS: 项塍麒螯 蝈牦?镱腩驽龛?蝮腧栾?
			if ((PPTOOLTIP_HELP == m_nNextTooltipType) || 
				(PPTOOLTIP_MENU == m_nNextTooltipType))
				pt = m_ptOriginal;
			else GetCursorPos(&pt);

			if ((pt.x != m_ptOriginal.x) || (pt.y != m_ptOriginal.y))
			{
				//ENG: If mouse coordinates was changed
				//RUS: 篷腓 牦瘃铕 皲忤眢腭, 蝾 箜梓蝾骅螯 蝮腧栾
				TRACE(_T("OnTimerShow(HideTooltip)\n"));
				HideTooltip();
			}
			else if (PPTOOLTIP_STATE_HIDEN == m_nTooltipState)
			{
				TRACE(_T("OnTimerShow(Showing)\n"));
				m_nTooltipState = PPTOOLTIP_STATE_SHOWING;
				//Display first step
				PrepareDisplayTooltip(&m_ptOriginal);

				//Fade In effect
				if ((SHOWEFFECT_FADEINOUT == m_dwShowEffect) && m_dwTimeFadeIn)
				{
					TRACE(_T("OnTimerShow(FadeIn)\n"));
					SetTimer(TIMER_SHOWING, m_dwTimeFadeIn, NULL); //Fade in showing was enabled
				}
				else
				{
					TRACE(_T("OnTimerShow(Shown)\n"));
					m_nTooltipState = PPTOOLTIP_STATE_SHOWN; //Tooltip is already show
					if (m_dwTimeAutoPop && !(m_tiNextTool.nBehaviour & PPTOOLTIP_DISABLE_AUTOPOP))
						SetTimer(TIMER_HIDE, m_dwTimeAutoPop, NULL); //Hiding by timer was enabled
				} //if
			} //if
			break;
		case TIMER_SHOWING:
			TRACE(_T("OnTimerFadeIn(Current Transparency=%d )\n"), m_dwCurTransparency);
			//ENG: If fade-in effect was finished then sets minimum transparency
			//RUS: 篷腓 汨 翦牝?镫噔眍泐 镱赅玎 桉麇痫囗? 蝾 篑蜞眍忤螯 扈龛爨朦眢?镳铉疣黜铖螯
			if (m_dwCurTransparency > (PERCENT_MIN_TRANSPARENCY + PERCENT_STEP_FADEIN))
				m_dwCurTransparency -= PERCENT_STEP_FADEIN;
			else m_dwCurTransparency = PERCENT_MIN_TRANSPARENCY;

			if (m_dwCurTransparency <= m_tiDisplayed.nTransparency)
			{
				//ENG: Kills showing timer and sets a tooltip's state as SHOWN
				//RUS: 俞桠噱?蜞殪屦 镫噔眍泐 镱赅玎 ?篑蜞磬怆桠噱?耦耱?龛?蝮腧栾?赅?SHOWN
				m_dwCurTransparency = m_tiDisplayed.nTransparency;
				KillTimer(TIMER_SHOWING);
				m_nTooltipState = PPTOOLTIP_STATE_SHOWN;
				//ENG: Starts timer to auto pop of the tooltip
				//RUS: 青矬耜 蜞殪屦?磬 噔蝾爨蜩麇耜铄 耦牮桢 蝮腧栾?
				SetAutoPopTimer();
			} //if
			//ENG: Redraw tooltip with new transparency factor
			//RUS: 襄疱痂耦忄螯 蝈牦?蝮腧栾 ?眍恹?觐翳鲨屙蝾?镳铉疣黜铖蜩
			OnRedrawTooltip(NULL, m_dwCurTransparency);
			break;	
		case TIMER_HIDE:
			TRACE(_T("OnTimerHide()\n"));
			//ENG: Kill all timers except HIDING timer
			//RUS: 俞桠噱?怦?蜞殪屦?玎 桉觌屙桢?蜞殪屦?HIDING
			KillTimer(TIMER_SHOW);
			KillTimer(TIMER_SHOWING);
			KillTimer(TIMER_HIDE);
			//ENG: If hiding timer don't start
			//RUS: 橡钼屦屐 玎矬?腓 蜞殪屦 耦牮? 蝮腧栾?
			if (PPTOOLTIP_STATE_HIDING != m_nTooltipState)
			{
				m_nTooltipState = PPTOOLTIP_STATE_HIDING;
				if ((SHOWEFFECT_FADEINOUT == m_dwHideEffect) && m_dwTimeFadeOut)
				{
					//ENG: If fade-out effect enabled and setted fade-out timestep
					//RUS: 篷腓 翦牝 镫噔眍泐 耦牮? 疣琊屮屙 ?箨噻囗?怵屐 汔 耦牮?
					SetTimer(TIMER_HIDING, m_dwTimeFadeOut, NULL);
				}
				else
				{
					//ENG: Sets a maximum transparency and to stops a hiding of a tooltip
					//RUS: 玉蜞磬怆桠噱?爨犟桁嚯簋 镳铉疣黜铖螯 ?铖蜞磬怆桠噱?耦牮桢
					m_dwCurTransparency = PERCENT_MAX_TRANSPARENCY;
					OnTimer(TIMER_HIDING);
				} //if
			} //if
			break;
		case TIMER_HIDING:
			TRACE(_T("OnTimerFadeOut(Current Transparency=%d)\n"), m_dwCurTransparency);
			//ENG: If fade-out effect was finished then sets maximum transparency
			//RUS: 篷腓 汨 翦牝?镫噔眍泐 耦牮? 桉麇痫囗? 蝾 篑蜞眍忤螯 爨犟桁嚯簋 镳铉疣黜铖螯
			if (m_dwCurTransparency < (PERCENT_MAX_TRANSPARENCY - PERCENT_STEP_FADEOUT))
				m_dwCurTransparency += PERCENT_STEP_FADEOUT;
			else m_dwCurTransparency = PERCENT_MAX_TRANSPARENCY;

			if (PERCENT_MAX_TRANSPARENCY == m_dwCurTransparency)
			{
				//ENG: Kills hiding timer and hides a tooltip
				//RUS: 俞桠噱?蜞殪屦 镫噔眍泐 耦牮? ?镳麇?铌眍 蝮腧栾?
				KillTimer(TIMER_HIDING);
				if (m_tiDisplayed.nBehaviour & PPTOOLTIP_MULTIPLE_SHOW)
				{
					//If for tool to set a multiple show then reset last window
					m_hwndDisplayedTool = NULL;
					m_tiDisplayed.rectBounds.SetRectEmpty();
				} //if
				ShowWindow(SW_HIDE);
				m_nTooltipState = PPTOOLTIP_STATE_HIDEN;
				if (m_bNextToolExist)
				{
					//ENG: If next tooltip is exist then starts show
					//RUS: 篷腓 耋耱怏弪 镱溷铗钼脲眄 蝮腧栾, 蝾 磬鬣螯 邈?铗钺疣驽龛?
					m_bNextToolExist = FALSE;
					//				m_nTooltipType = m_nNextTooltipType;
					//				m_nNextTooltipType = PPTOOLTIP_NORMAL;
					if (m_bDelayNextTool) SetTimer(TIMER_SHOW, m_dwTimeInitial, NULL);
					else OnTimer(TIMER_SHOW);
				}
				else
				{
					//ENG: If next tooltip wasn't exist
					//RUS: 篷腓 镱溷铗钼脲眄 蝮腧栾 礤 耋耱怏弪
					m_nTooltipType = PPTOOLTIP_NORMAL;
					m_nNextTooltipType = PPTOOLTIP_NORMAL;
				} //if
			}
			else 
			{
				//ENG: Redraw tooltip with new transparency factor
				//RUS: 襄疱痂耦忄螯 蝈牦?蝮腧栾 ?眍恹?觐翳鲨屙蝾?镳铉疣黜铖蜩
				OnRedrawTooltip(NULL, m_dwCurTransparency);
			} //if
			break;	
		case TIMER_ANIMATION:
			if (IsVisible() && (PPTOOLTIP_STATE_SHOWN == m_nTooltipState))
			{
				if(m_drawer.OnTimer())
					OnRedrawTooltip(NULL, m_dwCurTransparency);
			} //if
			break;
		default:
			CWnd::OnTimer(nIDEvent);
			break;
		} //switch
	} //End of the WM_TIMER handler

	void CPPToolTip::HideTooltip()
	{
		TRACE (_T("CPPToolTip::HideTooltip(CurState=%d)\n"), m_nTooltipState);
		switch(m_nTooltipState)
		{
		case PPTOOLTIP_STATE_SHOWING:
			//ENG: Kill showing tooltip
			//RUS: 篷腓 蝮腧栾 蝾朦觐 铗狃噫噱蝰, 蝾 镳尻疣屐 邈?铗钺疣驵螯
			KillTimer(TIMER_SHOWING);
		case PPTOOLTIP_STATE_SHOWN:
			//ENG: Hiding a tooltip
			//RUS: 橡麇?蝮腧栾
			OnTimer(TIMER_HIDE);
			break;
		} //switch
	} //End of HideTooltip

	void CPPToolTip::SetAutoPopTimer()
	{
		TRACE (_T("CPPToolTip::SetAutoPopTimer()\n"));
		if (m_dwTimeAutoPop && !(m_tiDisplayed.nBehaviour & PPTOOLTIP_DISABLE_AUTOPOP))
			SetTimer(TIMER_HIDE, m_dwTimeAutoPop, NULL);
	} //End of SetAutoPopTimer

	void CPPToolTip::KillTimers(DWORD dwIdTimer /* = NULL */)
	{
		TRACE (_T("CPPToolTip::KillTimers()\n"));
		if (dwIdTimer == NULL)
		{
			KillTimer(TIMER_SHOW);
			KillTimer(TIMER_HIDE);
			KillTimer(TIMER_SHOWING);
			KillTimer(TIMER_HIDING);
		}
		else 
		{
			KillTimer(dwIdTimer);
		} //if
	} //End KillTimers

	void CPPToolTip::Pop()
	{
		TRACE (_T("CPPToolTip::Pop()\n"));
		m_nTooltipState = PPTOOLTIP_STATE_HIDEN;
		m_nTooltipType = PPTOOLTIP_NORMAL;
		m_nNextTooltipType = PPTOOLTIP_NORMAL;
		KillTimers();
		if (IsVisible())
		{
			if (m_tiDisplayed.nBehaviour & PPTOOLTIP_MULTIPLE_SHOW)
			{
				//If for tool to set a multiple show then reset last window
				m_hwndDisplayedTool = NULL;
				m_tiDisplayed.rectBounds.SetRectEmpty();
			} //if
			ShowWindow(SW_HIDE);
		} //if
	} //End of Pop

	void CPPToolTip::PrepareDisplayTooltip(LPPOINT lpPoint)
	{
		TRACE (_T("CPPToolTip::PrepareDisplayTooltip()\n"));

		//Fills default members
		if (!(m_tiNextTool.nMask & PPTOOLTIP_MASK_STYLES))
			m_tiNextTool.nStyles = m_dwStyles;

		if (!(m_tiNextTool.nMask & PPTOOLTIP_MASK_EFFECT))
		{
			m_tiNextTool.nEffect = m_dwEffectBk;
			m_tiNextTool.nGranularity = m_nGranularity;
		} //if

		if (!(m_tiNextTool.nMask & PPTOOLTIP_MASK_COLORS))
		{
			m_tiNextTool.crBegin = m_clrBeginBk;
			m_tiNextTool.crMid = m_clrMidBk;
			m_tiNextTool.crEnd = m_clrEndBk;
		} //if

		if (!(m_tiNextTool.nMask & PPTOOLTIP_MASK_DIRECTION))
			m_tiNextTool.nDirection = m_dwDirection;

		if (!(m_tiNextTool.nMask & PPTOOLTIP_MASK_BEHAVIOUR))
			m_tiNextTool.nBehaviour = m_dwBehaviour;

		if (!(m_tiNextTool.nMask & PPTOOLTIP_MASK_TRANSPARENCY))
			m_tiNextTool.nTransparency = m_nTransparency;

		//Send notify
		POINT pt = *lpPoint; //Pointer in screen coordinates
		SendNotify(&pt, m_tiNextTool);

		//If string and icon are not exist then exit
		if (m_tiNextTool.sTooltip.IsEmpty())
			return;

		//calculate the width and height of the box dynamically
		CDC * pDC = GetDC();
		ASSERT(pDC->GetSafeHdc());

		CSize sz (0, 0);
		m_drawer.PrepareOutput(pDC->GetSafeHdc(), m_tiNextTool.sTooltip, &sz);

		m_rcTipArea.SetRect(0, 0, sz.cx, sz.cy);
		m_rcTooltip = m_rcTipArea;

		//Inflates on MARGIN_CX and MARGIN_CY sizes
		m_rcTipArea.OffsetRect(m_nSizes[PPTTSZ_MARGIN_CX], m_nSizes[PPTTSZ_MARGIN_CY]);
		m_rcTooltip.InflateRect(0, 0, 2 * m_nSizes[PPTTSZ_MARGIN_CX], 2 * m_nSizes[PPTTSZ_MARGIN_CY]);

		//Inflates on 
		//Gets tooltip's rect with anchor
		CPoint ptAnchor;
		m_dwCurDirection = GetTooltipDirection(m_tiNextTool.nDirection, pt, ptAnchor, m_rcTooltip, m_rcBoundsTooltip, m_rcTipArea);

		//ENG: Clears resources
		//RUS: 西棂噱?疱耋瘃?
		FreeResources();

		//ENG: Creates a new region of the window
		//RUS: 杨玟噱?眍恹?疱汨铐 铌磬
		m_hrgnTooltip = GetTooltipRgn(m_dwCurDirection, ptAnchor.x, ptAnchor.y, m_rcBoundsTooltip.Width(), m_rcBoundsTooltip.Height());

		CRect rect = m_rcBoundsTooltip;

		//ENG: Creates a background bitmap
		//RUS: 杨玟噱?徼蜢囡 纛磬 蝮腧栾?
		m_hBitmapBk = ::CreateCompatibleBitmap(pDC->GetSafeHdc(), rect.Width(), rect.Height());
		HDC hMemDC = ::CreateCompatibleDC(pDC->GetSafeHdc());

		//ENG: Creates a background of the tooltip's body
		//RUS: 杨玟囗桢 纛磬 蝈豚 蝮腧栾?
		HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hMemDC, m_hBitmapBk);
		m_drawer.GetDrawManager()->FillEffect(hMemDC, 
			m_tiNextTool.nEffect, 
			m_rcTooltip,
			m_tiNextTool.crBegin,
			m_tiNextTool.crMid,
			m_tiNextTool.crEnd,
			m_tiNextTool.nGranularity,
			5);
		//ENG: Fills an anchor
		//RUS: 青镱腠屐 觐瘘 蝮腧栾?
		switch (m_dwCurDirection)
		{
		case PPTOOLTIP_LEFTEDGE_TOP:
		case PPTOOLTIP_LEFTEDGE_VCENTER:
		case PPTOOLTIP_LEFTEDGE_BOTTOM:
			m_drawer.GetDrawManager()->MultipleCopy(hMemDC, m_rcBoundsTooltip.left, m_rcBoundsTooltip.top, m_rcTooltip.left - m_rcBoundsTooltip.left, m_rcBoundsTooltip.Height(),
				hMemDC, m_rcTooltip.left + 1, m_rcBoundsTooltip.top, 1, m_rcBoundsTooltip.Height());
			break;
		case PPTOOLTIP_RIGHTEDGE_TOP:
		case PPTOOLTIP_RIGHTEDGE_VCENTER:
		case PPTOOLTIP_RIGHTEDGE_BOTTOM:
			m_drawer.GetDrawManager()->MultipleCopy(hMemDC, m_rcTooltip.right, m_rcBoundsTooltip.top, m_rcBoundsTooltip.right - m_rcTooltip.right, m_rcBoundsTooltip.Height(),
				hMemDC, m_rcTooltip.right - 1, m_rcBoundsTooltip.top, 1, m_rcBoundsTooltip.Height());
			break;
		case PPTOOLTIP_BOTTOMEDGE_LEFT:
		case PPTOOLTIP_BOTTOMEDGE_CENTER:
		case PPTOOLTIP_BOTTOMEDGE_RIGHT:
			m_drawer.GetDrawManager()->MultipleCopy(hMemDC, m_rcBoundsTooltip.left, m_rcTooltip.bottom, m_rcBoundsTooltip.Width(), m_rcBoundsTooltip.bottom - m_rcTooltip.bottom,
				hMemDC, m_rcBoundsTooltip.left, m_rcTooltip.bottom - 1, m_rcBoundsTooltip.Width(), 1);
			break;
		case PPTOOLTIP_TOPEDGE_LEFT:
		case PPTOOLTIP_TOPEDGE_CENTER:
		case PPTOOLTIP_TOPEDGE_RIGHT:
			m_drawer.GetDrawManager()->MultipleCopy(hMemDC, m_rcBoundsTooltip.left, m_rcBoundsTooltip.top, m_rcBoundsTooltip.Width(), m_rcTooltip.top - m_rcBoundsTooltip.top,
				hMemDC, m_rcBoundsTooltip.left, m_rcTooltip.top + 1, m_rcBoundsTooltip.Width(), 1);
			break;
		} //switch

		::SelectObject(hMemDC, hOldBitmap);
		::DeleteDC(hMemDC);

		ReleaseDC(pDC);

		//ENG: Calculate the tooltip's placement on the screen
		//RUS: 蔓麒耠屙桢 镱腩驽龛 蝮腧栾?磬 疣礤
		rect.left = pt.x - ptAnchor.x;
		rect.top = pt.y - ptAnchor.y;
		rect.right = rect.left + m_rcBoundsTooltip.Width();
		rect.bottom = rect.top + m_rcBoundsTooltip.Height();

		//ENG: If fade-in effect ia available
		//RUS: 篷腓 镫噔眍?铗钺疣驽龛?漕耱箫眍
		if ((SHOWEFFECT_FADEINOUT == m_dwShowEffect) && m_dwTimeFadeIn)
			m_dwCurTransparency = 100;
		else
			m_dwCurTransparency = m_tiNextTool.nTransparency;

		HRGN hrgnWindow = ::CreateRectRgn(0, 0, 0, 0);
		if (m_szOffsetShadow.cx || m_szOffsetShadow.cy)
		{
			//ENG: If shadow will drawn
			//RUS: 篷腓 蝈睃 狍溴?铗钺疣驵螯?
			HRGN hrgnShadow = ::CreateRectRgn(0, 0, 0, 0);
			::CombineRgn(hrgnShadow, m_hrgnTooltip, hrgnShadow, RGN_COPY);
			::OffsetRgn(hrgnShadow, m_szOffsetShadow.cx, m_szOffsetShadow.cy);
			::CombineRgn(hrgnWindow, m_hrgnTooltip, hrgnShadow, RGN_OR);
			::DeleteObject(hrgnShadow);

			//ENG: Increments the sizes of tooltip to drawing a shadow
			//RUS: 逾咫梓桠噱?疣珈屦?蝮腧栾?潆 痂耦忄龛 蝈龛
			m_rcBoundsTooltip.right += m_szOffsetShadow.cx;
			m_rcBoundsTooltip.bottom += m_szOffsetShadow.cy;
		}
		else
		{
			//ENG: The current window has not a shadow
			//RUS: 义牦?铌眍 礤 桁邋?蝈龛
			::CombineRgn(hrgnWindow, m_hrgnTooltip, NULL, RGN_COPY);
		}//if

		//ENG: Applies a region
		//RUS: 橡桁屙屐 疱汨铐
		SetWindowRgn(hrgnWindow, FALSE);

		//ENG: Sets a tooltip on the screen
		//RUS: 玉蜞磬怆桠噱?蝮腧栾 磬 疣礤
		if (PPTOOLTIP_MENU == m_nTooltipType) 
		{
			SetWindowPos(NULL, 
				rect.left, rect.top,
				m_rcBoundsTooltip.Width(), 
				m_rcBoundsTooltip.Height(),
				SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER/*|SWP_NOCOPYBITS*/);
		}
		else
		{
			SetWindowPos(NULL, 
				rect.left, rect.top,
				m_rcBoundsTooltip.Width(), 
				m_rcBoundsTooltip.Height(),
				SWP_SHOWWINDOW|SWP_NOACTIVATE/*|SWP_NOCOPYBITS*/);
		}
	} //End of PrepareDisplayTooltip

	void CPPToolTip::FreeResources()
	{
		if (NULL != m_hrgnTooltip)
		{
			::DeleteObject(m_hrgnTooltip);
			m_hrgnTooltip = NULL;
		} //if

		if (NULL != m_hBitmapBk)
		{
			::DeleteObject(m_hBitmapBk);
			m_hBitmapBk = NULL;
		} //if

		if (NULL != m_hUnderTooltipBk)
		{
			::DeleteObject(m_hUnderTooltipBk);
			m_hUnderTooltipBk = NULL;
		} //if
	} //End of FreeResources

	void CPPToolTip::OutputTooltipOnScreen(LPPOINT lpPoint, HDC hDC /* = NULL */)
	{
		TRACE(_T("OutputTooltipOnScreen()\n"));
		CRect rect = m_rcBoundsTooltip;
		rect.OffsetRect(*lpPoint);
		//m_dwCurDirection = GetTooltipDirection(m_tiNextTool.nDirection, &pt, &ptAnchor, m_rcTooltip, m_rcBoundsTooltip, m_rcTipArea);
		MoveWindow(rect);
	} //End OutputTooltipOnScreen

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::GetTooltipDirection()
	//		Gets a real direction of a tooltip.
	//------------------------------------------------------------------
	// Parameters:
	//		dwDirection		- A default direction of a tooltip. 
	//		lpPoint			- A mouse position in the screen coordinates.
	//		lpAnchor		- An anchor position in the client coordinates
	//      rcBody			- A rectangle of a tooltip's body in the client coordinates
	//		rcFull			- A rectangle of a full tooltip in the client coordinates
	//		rcTipArea		- A rectangle of a tooltip's info area in the client coordinates
	// Return values:
	//		A real direction of a tooltip
	//------------------------------------------------------------------
	// Explanation:
	//    0
	//  0 +------------------------------------+
	//    |                                    |
	//    |             rcBody                 |
	//    |                                    |
	//    |  +------------------------------+  |
	//    |  |                              |  |
	//    |  |         rcTipArea            |  |
	//    |  |                              |  |
	//    |  +------------------------------+  |
	//    |                                    |
	//    +--+...------------------------------+
	//    :  |  /                              :
	//    :  | /        rcFull                 :
	//    :..|/................................:
	//       +- lpAnchor
	//
	////////////////////////////////////////////////////////////////////
	DWORD CPPToolTip::GetTooltipDirection(DWORD dwDirection, const CPoint & ptPoint, CPoint & ptAnchor, CRect & rcBody, CRect & rcFull, CRect & rcTipArea)
	{
		//ENG: Get Window's rectangle. The whole virtual desktop .... not only the primary screen.JFN
		//RUS: 项塍鬣屐 镱腠 镳祛筱铍桕 疣磬 Windows
		CRect rWindow;
		rWindow.left    = 0; //::GetSystemMetrics(SM_XVIRTUALSCREEN);
		rWindow.top     = 0; //::GetSystemMetrics(SM_YVIRTUALSCREEN);
		rWindow.right   = rWindow.left + ::GetSystemMetrics(SM_CXSCREEN); //::GetSystemMetrics(SM_CXVIRTUALSCREEN);
		rWindow.bottom  = rWindow.top + ::GetSystemMetrics(SM_CYSCREEN); //::GetSystemMetrics(SM_CYVIRTUALSCREEN);

		//-------------------------------------------
		//ENG: Initializing size of the bounds rect
		//RUS: 软桷栲腓玎鲨 镱腠钽?疣珈屦?钽疣龛麒忄邈?蝮腧栾 镳祛筱铍桕?
		rcFull = rcBody;
		switch(dwDirection) 
		{
		case PPTOOLTIP_LEFTEDGE_TOP:
		case PPTOOLTIP_LEFTEDGE_VCENTER:
		case PPTOOLTIP_LEFTEDGE_BOTTOM:
			rcFull.right += m_nSizes [PPTTSZ_HEIGHT_ANCHOR];
			break;
		case PPTOOLTIP_RIGHTEDGE_TOP:
		case PPTOOLTIP_RIGHTEDGE_VCENTER:
		case PPTOOLTIP_RIGHTEDGE_BOTTOM:
			rcFull.right += m_nSizes [PPTTSZ_HEIGHT_ANCHOR];
			break;
		case PPTOOLTIP_BOTTOMEDGE_LEFT:
		case PPTOOLTIP_BOTTOMEDGE_CENTER:
		case PPTOOLTIP_BOTTOMEDGE_RIGHT:
			rcFull.bottom += m_nSizes [PPTTSZ_HEIGHT_ANCHOR];
			break;
		case PPTOOLTIP_TOPEDGE_LEFT:
		case PPTOOLTIP_TOPEDGE_CENTER:
		case PPTOOLTIP_TOPEDGE_RIGHT:
			rcFull.bottom += m_nSizes [PPTTSZ_HEIGHT_ANCHOR];
			break;
		} //switch

		//---------------------------------------------------
		//ENG: If needed change a horizontal direction
		//RUS: 橡钼屦赅 泐痂珙眚嚯 疣珈屦钼 磬 镱镟溧龛??疣?
		CPoint pt(ptPoint);
		switch(dwDirection) 
		{
		case PPTOOLTIP_LEFTEDGE_TOP:
		case PPTOOLTIP_LEFTEDGE_VCENTER:
		case PPTOOLTIP_LEFTEDGE_BOTTOM:
			pt.x += rcFull.right;
			if (pt.x > rWindow.right)
				dwDirection ^= 0x10;
			break;
		case PPTOOLTIP_RIGHTEDGE_TOP:
		case PPTOOLTIP_RIGHTEDGE_VCENTER:
		case PPTOOLTIP_RIGHTEDGE_BOTTOM:
			pt.x -= rcFull.right;
			if (pt.x < rWindow.left)
				dwDirection ^= 0x10;
			break;
		case PPTOOLTIP_BOTTOMEDGE_LEFT:
		case PPTOOLTIP_TOPEDGE_LEFT:
			pt.x += rcFull.right;
			pt.x -= m_nSizes [PPTTSZ_MARGIN_ANCHOR];
			if (pt.x > rWindow.right)
			{
				pt.x = ptPoint.x - rcFull.right;
				pt.x += m_nSizes [PPTTSZ_MARGIN_ANCHOR];
				if (pt.x < rWindow.left)
					dwDirection |= 0x02;
				else
					dwDirection ^= 0x01;
			} //if
			break;
		case PPTOOLTIP_BOTTOMEDGE_RIGHT:
		case PPTOOLTIP_TOPEDGE_RIGHT:
			pt.x -= rcFull.right;
			pt.x += m_nSizes [PPTTSZ_MARGIN_ANCHOR];
			if (pt.x < rWindow.left)
			{
				pt.x = ptPoint.x + rcFull.right;
				pt.x -= m_nSizes [PPTTSZ_MARGIN_ANCHOR];
				if (pt.x > rWindow.right)
					dwDirection ^= 0x03;
				else
					dwDirection ^= 0x01;
			} //if
			break;
		case PPTOOLTIP_BOTTOMEDGE_CENTER:
		case PPTOOLTIP_TOPEDGE_CENTER:
			if ((ptPoint.x - rWindow.left) <= m_nSizes [PPTTSZ_MARGIN_ANCHOR])
				dwDirection ^= 0x02;
			else if ((rWindow.right - ptPoint.x) <= m_nSizes [PPTTSZ_MARGIN_ANCHOR])
				dwDirection ^= 0x03;
			break;
		} //switch

		//---------------------------------------------------
		//ENG: If needed change a vertical direction
		//RUS: 橡钼屦赅 忮痱桕嚯 疣珈屦钼 磬 镱镟溧龛??疣?
		switch(dwDirection) 
		{
		case PPTOOLTIP_LEFTEDGE_TOP:
		case PPTOOLTIP_RIGHTEDGE_TOP:
			pt.y += rcFull.bottom;
			pt.y -= m_nSizes [PPTTSZ_MARGIN_ANCHOR];
			if (pt.y > rWindow.bottom)
			{
				pt.y = ptPoint.y - rcFull.bottom;
				pt.y += m_nSizes [PPTTSZ_MARGIN_ANCHOR];
				if (pt.y < rWindow.top)
					dwDirection |= 0x02;
				else
					dwDirection ^= 0x01;
			} //if
			break;
		case PPTOOLTIP_LEFTEDGE_BOTTOM:
		case PPTOOLTIP_RIGHTEDGE_BOTTOM:
			pt.y -= rcFull.bottom;
			pt.y += m_nSizes [PPTTSZ_MARGIN_ANCHOR];
			if (pt.y < rWindow.top)
			{
				pt.y = ptPoint.y + rcFull.bottom;
				pt.y -= m_nSizes [PPTTSZ_MARGIN_ANCHOR];
				if (pt.y > rWindow.bottom)
					dwDirection ^= 0x03;
				else
					dwDirection ^= 0x01;
			} //if
			break;
		case PPTOOLTIP_LEFTEDGE_VCENTER:
		case PPTOOLTIP_RIGHTEDGE_VCENTER:
			if ((ptPoint.y - rWindow.top) <= m_nSizes [PPTTSZ_MARGIN_ANCHOR])
				dwDirection ^= 0x02;
			else if ((rWindow.bottom - ptPoint.y) <= m_nSizes [PPTTSZ_MARGIN_ANCHOR])
				dwDirection ^= 0x03;
			break;
		case PPTOOLTIP_BOTTOMEDGE_LEFT:
		case PPTOOLTIP_BOTTOMEDGE_CENTER:
		case PPTOOLTIP_BOTTOMEDGE_RIGHT:
			pt.y -= rcFull.bottom;
			if (pt.y < rWindow.top)
				dwDirection ^= 0x10;
			break;
		case PPTOOLTIP_TOPEDGE_LEFT:
		case PPTOOLTIP_TOPEDGE_CENTER:
		case PPTOOLTIP_TOPEDGE_RIGHT:
			pt.y += rcFull.bottom;
			if (pt.y > rWindow.bottom)
				dwDirection ^= 0x10;
			break;
		} //switch

		//---------------------------------------------------
		//ENG: Set the anchor's point
		//RUS: 玉蜞眍怅?觐铕滂磬螓 觐眵桕?
		switch(dwDirection) 
		{
		case PPTOOLTIP_LEFTEDGE_TOP:
		case PPTOOLTIP_LEFTEDGE_VCENTER:
		case PPTOOLTIP_LEFTEDGE_BOTTOM:
			ptAnchor.x = rcFull.left;
			break;
		case PPTOOLTIP_RIGHTEDGE_TOP:
		case PPTOOLTIP_RIGHTEDGE_VCENTER:
		case PPTOOLTIP_RIGHTEDGE_BOTTOM:
			ptAnchor.x = rcFull.right;
			break;
		case PPTOOLTIP_BOTTOMEDGE_LEFT:
		case PPTOOLTIP_BOTTOMEDGE_CENTER:
		case PPTOOLTIP_BOTTOMEDGE_RIGHT:
			ptAnchor.y = rcFull.bottom;
			break;
		case PPTOOLTIP_TOPEDGE_LEFT:
		case PPTOOLTIP_TOPEDGE_CENTER:
		case PPTOOLTIP_TOPEDGE_RIGHT:
			ptAnchor.y = rcFull.top;
			break;
		} //switch

		//
		switch(dwDirection) 
		{
		case PPTOOLTIP_LEFTEDGE_TOP:
		case PPTOOLTIP_RIGHTEDGE_TOP:
			ptAnchor.y = rcFull.top + m_nSizes [PPTTSZ_MARGIN_ANCHOR];
			break;
		case PPTOOLTIP_LEFTEDGE_BOTTOM:
		case PPTOOLTIP_RIGHTEDGE_BOTTOM:
			ptAnchor.y = rcFull.bottom - m_nSizes [PPTTSZ_MARGIN_ANCHOR];
			break;
		case PPTOOLTIP_LEFTEDGE_VCENTER:
		case PPTOOLTIP_RIGHTEDGE_VCENTER:
			ptAnchor.y = rcFull.bottom / 2;
			if ((ptPoint.y + rcFull.bottom / 2) <= rWindow.bottom)
			{
				if ((ptPoint.y - rcFull.bottom / 2) < rWindow.top)
					ptAnchor.y -= (rcFull.bottom / 2 - ptPoint.y + rWindow.top);
			}
			else if ((ptPoint.y - rcFull.bottom / 2) >= rWindow.top)
			{
				if ((ptPoint.y + rcFull.bottom / 2) > rWindow.bottom)
					ptAnchor.y += (ptPoint.y + rcFull.bottom / 2 - rWindow.bottom);
			} //if
			break;
		case PPTOOLTIP_BOTTOMEDGE_LEFT:
		case PPTOOLTIP_TOPEDGE_LEFT:
			ptAnchor.x = rcFull.left + m_nSizes [PPTTSZ_MARGIN_ANCHOR];
			break;
		case PPTOOLTIP_BOTTOMEDGE_RIGHT:
		case PPTOOLTIP_TOPEDGE_RIGHT:
			ptAnchor.x = rcFull.right - m_nSizes [PPTTSZ_MARGIN_ANCHOR];
			break;
		case PPTOOLTIP_BOTTOMEDGE_CENTER:
		case PPTOOLTIP_TOPEDGE_CENTER:
			ptAnchor.x = rcFull.right / 2;
			if ((ptPoint.x + rcFull.right / 2) <= rWindow.right)
			{
				if ((ptPoint.x - rcFull.right / 2) < rWindow.left)
					ptAnchor.x -= (rcFull.right / 2 - ptPoint.x + rWindow.left);
			}
			else if ((ptPoint.x - rcFull.right / 2) >= rWindow.left)
			{
				if ((ptPoint.x + rcFull.right / 2) > rWindow.right)
					ptAnchor.x += (ptPoint.x + rcFull.right / 2 - rWindow.right);
			} //if
			break;
		} //switch

		//---------------------------------------------------
		//If needed offset anchor
		switch(dwDirection) 
		{
		case PPTOOLTIP_LEFTEDGE_TOP:
		case PPTOOLTIP_RIGHTEDGE_TOP:
		case PPTOOLTIP_LEFTEDGE_VCENTER:
		case PPTOOLTIP_RIGHTEDGE_VCENTER:
			if ((ptPoint.y - ptAnchor.y) < rWindow.top)
				ptAnchor.y = ptPoint.y - rWindow.top;
			break;
		case PPTOOLTIP_LEFTEDGE_BOTTOM:
		case PPTOOLTIP_RIGHTEDGE_BOTTOM:
			if ((ptPoint.y + rcFull.bottom - ptAnchor.y) > rWindow.bottom)
				ptAnchor.y = rcFull.bottom - rWindow.bottom + ptPoint.y;
			break;
		case PPTOOLTIP_BOTTOMEDGE_LEFT:
		case PPTOOLTIP_TOPEDGE_LEFT:
		case PPTOOLTIP_BOTTOMEDGE_CENTER:
		case PPTOOLTIP_TOPEDGE_CENTER:
			if ((ptPoint.x - ptAnchor.x) < rWindow.left)
				ptAnchor.x = ptPoint.x - rWindow.left;
			break;
		case PPTOOLTIP_BOTTOMEDGE_RIGHT:
		case PPTOOLTIP_TOPEDGE_RIGHT:
			if ((ptPoint.x + rcFull.right - ptAnchor.x) > rWindow.right)
				ptAnchor.x = rcFull.right - rWindow.right + ptPoint.x;
			break;
		} //switch

		//*!* I don't know why but without following lines application fails in Release mode!!!!
		CString str;
		str.Format("0x%08X", dwDirection);

		//---------------------------------------------
		// Offset the body rectangle
		switch(dwDirection) 
		{
		case PPTOOLTIP_LEFTEDGE_TOP:
		case PPTOOLTIP_LEFTEDGE_VCENTER:
		case PPTOOLTIP_LEFTEDGE_BOTTOM:
			rcTipArea.OffsetRect(m_nSizes [PPTTSZ_HEIGHT_ANCHOR], 0);
			rcBody.OffsetRect(m_nSizes [PPTTSZ_HEIGHT_ANCHOR], 0);
			break;
		case PPTOOLTIP_TOPEDGE_LEFT:
		case PPTOOLTIP_TOPEDGE_CENTER:
		case PPTOOLTIP_TOPEDGE_RIGHT:
			rcTipArea.OffsetRect(0, m_nSizes [PPTTSZ_HEIGHT_ANCHOR]);
			rcBody.OffsetRect(0, m_nSizes [PPTTSZ_HEIGHT_ANCHOR]);
			break;
		} //switch

		return dwDirection;
	} //End of GetTooltipDirection

	HRGN CPPToolTip::GetTooltipRgn(DWORD dwDirection, int x, int y, int nWidth, int nHeight)
	{
		HRGN hRgn = NULL;

		HRGN hrgnBody = NULL;
		CRect rcBody(0, 0, nWidth, nHeight);

		HRGN hrgnAnchor = NULL;
		POINT ptAnchor [3];
		ptAnchor [0].x = x;
		ptAnchor [0].y = y;

		HRGN hrgnRect = NULL;

		//------------------------------
		switch(dwDirection) 
		{
		case PPTOOLTIP_LEFTEDGE_TOP:
		case PPTOOLTIP_LEFTEDGE_VCENTER:
		case PPTOOLTIP_LEFTEDGE_BOTTOM:
			rcBody.left += m_nSizes [PPTTSZ_HEIGHT_ANCHOR];
			ptAnchor [1].x = ptAnchor [2].x = rcBody.left;
			break;
		case PPTOOLTIP_RIGHTEDGE_TOP:
		case PPTOOLTIP_RIGHTEDGE_VCENTER:
		case PPTOOLTIP_RIGHTEDGE_BOTTOM:
			rcBody.right -= m_nSizes [PPTTSZ_HEIGHT_ANCHOR];
			ptAnchor [1].x = ptAnchor [2].x = rcBody.right;
			break;
		case PPTOOLTIP_TOPEDGE_LEFT:
		case PPTOOLTIP_TOPEDGE_CENTER:
		case PPTOOLTIP_TOPEDGE_RIGHT:
			rcBody.top += m_nSizes [PPTTSZ_HEIGHT_ANCHOR];
			ptAnchor [1].y = ptAnchor [2].y = rcBody.top;
			break;
		case PPTOOLTIP_BOTTOMEDGE_LEFT:
		case PPTOOLTIP_BOTTOMEDGE_CENTER:
		case PPTOOLTIP_BOTTOMEDGE_RIGHT:
			rcBody.bottom -= m_nSizes [PPTTSZ_HEIGHT_ANCHOR];
			ptAnchor [1].y = ptAnchor [2].y = rcBody.bottom;
			break;
		} //switch

		//------------------------------
		switch(dwDirection) 
		{
		case PPTOOLTIP_LEFTEDGE_TOP:
		case PPTOOLTIP_RIGHTEDGE_TOP:
			ptAnchor [1].y = rcBody.top + m_nSizes [PPTTSZ_MARGIN_ANCHOR];
			ptAnchor [2].y = ptAnchor [1].y + m_nSizes [PPTTSZ_WIDTH_ANCHOR];
			break;
		case PPTOOLTIP_LEFTEDGE_BOTTOM:
		case PPTOOLTIP_RIGHTEDGE_BOTTOM:
			ptAnchor [1].y = rcBody.bottom - m_nSizes [PPTTSZ_MARGIN_ANCHOR];
			ptAnchor [2].y = ptAnchor [1].y - m_nSizes [PPTTSZ_WIDTH_ANCHOR];
			break;
		case PPTOOLTIP_LEFTEDGE_VCENTER:
		case PPTOOLTIP_RIGHTEDGE_VCENTER:
			ptAnchor [1].y = ptAnchor [0].y - m_nSizes [PPTTSZ_WIDTH_ANCHOR] / 2;
			//		ptAnchor [1].y = rcBody.top + (rcBody.Height() - m_nSizes [PPTTSZ_WIDTH_ANCHOR]) / 2;
			ptAnchor [2].y = ptAnchor [1].y + m_nSizes [PPTTSZ_WIDTH_ANCHOR];
			break;
		case PPTOOLTIP_TOPEDGE_LEFT:
		case PPTOOLTIP_BOTTOMEDGE_LEFT:
			ptAnchor [1].x = rcBody.left + m_nSizes [PPTTSZ_MARGIN_ANCHOR];
			ptAnchor [2].x = ptAnchor [1].x + m_nSizes [PPTTSZ_WIDTH_ANCHOR];
			break;
		case PPTOOLTIP_TOPEDGE_RIGHT:
		case PPTOOLTIP_BOTTOMEDGE_RIGHT:
			ptAnchor [1].x = rcBody.right - m_nSizes [PPTTSZ_MARGIN_ANCHOR];
			ptAnchor [2].x = ptAnchor [1].x - m_nSizes [PPTTSZ_WIDTH_ANCHOR];
			break;
		case PPTOOLTIP_TOPEDGE_CENTER:
		case PPTOOLTIP_BOTTOMEDGE_CENTER:
			ptAnchor [1].x = ptAnchor [0].x - m_nSizes [PPTTSZ_WIDTH_ANCHOR] / 2;
			//		ptAnchor [1].x = rcBody.left + (rcBody.Width() - m_nSizes [PPTTSZ_WIDTH_ANCHOR]) / 2;
			ptAnchor [2].x = ptAnchor [1].x + m_nSizes [PPTTSZ_WIDTH_ANCHOR];
			break;
		} //switch

		//------------------------------
		//Gets the tooltip body's region
		hrgnBody = ::CreateRoundRectRgn(rcBody.left, rcBody.top, rcBody.right + 1, rcBody.bottom + 1, 
			m_nSizes[PPTTSZ_ROUNDED_CX], m_nSizes[PPTTSZ_ROUNDED_CY]);

		//Gets the tooltip anchor's region
		if (m_nSizes [PPTTSZ_HEIGHT_ANCHOR] && m_nSizes [PPTTSZ_WIDTH_ANCHOR])
			hrgnAnchor = ::CreatePolygonRgn(ptAnchor, 3, ALTERNATE);
		else
			hrgnAnchor = ::CreateRectRgn(0, 0, 0, 0);

		hRgn = ::CreateRectRgn(0, 0, 0, 0);
		::CombineRgn(hRgn, hrgnBody, hrgnAnchor, RGN_OR);

		if (NULL != hrgnBody)
			::DeleteObject(hrgnBody);
		if (NULL != hrgnAnchor)
			::DeleteObject(hrgnAnchor);

		return hRgn;
	} //End GetTooltipRgn

	BOOL CPPToolTip::IsCursorOverTooltip() const
	{
		ASSERT(m_hParentWnd);

		// Is tooltip visible?
		if (!IsVisible() || !IsWindow(m_hWnd))
			return FALSE;

		POINT pt;
		GetCursorPos(&pt);

		CPPToolTip * pWnd = (CPPToolTip*)WindowFromPoint(pt);

		return (pWnd == this);
	}

	HWND CPPToolTip::GetWndFromPoint(const LPPOINT lpPoint, PPTOOLTIP_INFO & ti, BOOL bCheckTool /* = TRUE */)
	{
		// the default implementation of tooltips just calls WindowFromPoint
		// which does not work for certain kinds of combo boxes
		CPoint pt = *lpPoint;
		::ClientToScreen(m_hParentWnd, &pt);
		HWND hWnd = ::WindowFromPoint(pt);
		if (NULL != hWnd)
		{
			// try to hit combobox instead of edit control for CBS_DROPDOWN styles
			HWND hWndTemp = ::GetParent(hWnd);
			if (NULL != hWndTemp)
			{
				if (!IsComboBoxControl(hWndTemp, CBS_DROPDOWN))
				{
					// handle special case of disabled child windows
					::ScreenToClient(hWnd, &pt);
					hWndTemp = ::ChildWindowFromPoint(hWnd, pt);
					if (NULL == hWndTemp)
						return NULL;
					if ((!::IsWindowEnabled(hWndTemp)) && bCheckTool)
						return NULL;
				} //if

				if (FindTool(hWndTemp, &pt, ti) || !bCheckTool)
					return hWndTemp;
			} //if
		} //if

		return NULL;
	} //End GetWndFromPoint

	BOOL CPPToolTip::IsComboBoxControl(HWND hWnd, UINT nStyle)
	{
		if (hWnd == NULL)
			return FALSE;
		// do cheap style compare first
		if ((UINT)(::GetWindowLong(hWnd, GWL_STYLE) & 0x0F) != nStyle)
			return FALSE;

		// do expensive classname compare next
		TCHAR szCompare[9];
		::GetClassName(hWnd, szCompare, 9);
		return lstrcmpi(szCompare, _T("combobox")) == 0;
	}

	CString CPPToolTip::GetDebugInfoTool(LPPOINT lpPoint)
	{
		PPTOOLTIP_INFO ti;
		HWND hWnd = GetWndFromPoint(lpPoint, ti, FALSE);
		HWND hParent = ::GetParent (hWnd);

		_TCHAR ch[128];
		CString str, strTemp;
		CString strOutput = _T("<table>");

		///////////////////////////////////////////////////////////////////
		//Table of a window
		strOutput += _T("<tr><td><font color=darkblue>Window</font><table border=1>");

		//1. Window's class name and Window Owner's class name
		::GetClassName (hWnd, ch, 128);
		strOutput += CreateDebugCell(_T("Class name"), ch);

		//2. Window's title and Window Owner's title
		::GetWindowText (hWnd, ch, 128);
		strOutput += CreateDebugCell(_T("Title"), ch);

		//3. Window's handle and Window Owner's handle
		str.Format(_T("0x%08X"), hWnd);
		strOutput += CreateDebugCell(_T("Handle"), str);

		//4. Window's ID
		str.Format(_T("%d"), GetWindowLong(hWnd, GWL_ID));
		strOutput += CreateDebugCell(_T("Control ID"), str);

		//5. Window's styles
		str.Format(_T("0x%08X"), (DWORD)::GetWindowLong (hWnd, GWL_STYLE));
		strOutput += CreateDebugCell(_T("Styles"), str);

		//6. Window's rect
		RECT rc; 
		::GetWindowRect(hWnd, &rc);
		str.Format(_T("(%d, %d)-(%d, %d)"), rc.left, rc.top, rc.right, rc.bottom);
		strOutput += CreateDebugCell(_T("RECT"), str);

		//7. Window's width
		str.Format(_T("%d"), rc.right - rc.left);
		strOutput += CreateDebugCell(_T("Width"), str);

		//8. Window's height
		str.Format(_T("%d"), rc.bottom - rc.top);
		strOutput += CreateDebugCell(_T("Height"), str);

		//9. Window's has tooltip
		HWND hwndTool = FindTool(lpPoint, ti);
		str = (NULL != hwndTool) ? _T("Yes") : _T("No");
		strOutput += CreateDebugCell(_T("Has Tooltip"), str);

		strOutput += _T("</table></td>");

		///////////////////////////////////////////////////////////////////
		//Table of a window owner
		strOutput += _T("<td><font color=darkblue>Window Owner</font><table border=1>");

		//1. Window's class name and Window Owner's class name
		if (NULL != hParent)
		{
			::GetClassName (hParent, ch, 128);
			str = GetMaxDebugString((CString)ch);
		} //if
		else str = _T("N/A");
		strOutput += CreateDebugCell(_T("Class name"), str);

		//2. Window's title and Window Owner's title
		if (NULL != hParent)
		{
			::GetWindowText (hParent, ch, 128);
			str = GetMaxDebugString((CString)ch);
		} //if
		else str = _T("N/A");
		strOutput += CreateDebugCell(_T("Title"), str);

		//3. Window's handle and Window Owner's handle
		str.Format(_T("0x%08X"), hParent);
		strOutput += CreateDebugCell(_T("Handle"), str);

		strOutput += _T("</table>");

		///////////////////////////////////////////////////////////////////
		//Table of a window owner
		strOutput += _T("<br><font color=darkblue>Mouse Cursor</font><table border=1>");

		//1.
		str.Format(_T("%d"), lpPoint->x);
		strOutput += CreateDebugCell(_T("X"), str);

		//2.
		str.Format(_T("%d"), lpPoint->y);
		strOutput += CreateDebugCell(_T("Y"), str);

		strOutput += _T("</table></td></tr></table>");

		///////////////////////////////////////////////////////////////////////////
		return strOutput;
	}

	CString CPPToolTip::CreateDebugCell(CString sTitle, LPCTSTR lpszDescription)
	{
		CString str;
		str.Format(_T("<tr><td width=70 bgcolor=buttonface>%s</td><td width=130 bgcolor=window>%s</td></tr>"), 
			sTitle, GetMaxDebugString(lpszDescription));
		return str;
	} //End of CreateDebugCell

	CString CPPToolTip::GetMaxDebugString(LPCTSTR lpszText)
	{
		CString str = (CString)lpszText;
		str.Replace(_T("<"), _T("?")); //Replaces the begins of the tags
		if (str.GetLength() > MAX_LENGTH_DEBUG_STRING)
		{
			str = str.Left(MAX_LENGTH_DEBUG_STRING - 4);
			str += _T(" ...");
		} //if

		return str;
	} //End of GetMaxDebugString

	HWND CPPToolTip::FindTool(const LPPOINT lpPoint, PPTOOLTIP_INFO & ti)
	{
		return GetWndFromPoint(lpPoint, ti, TRUE);
	} //End of FindTool

	BOOL CPPToolTip::FindTool(HWND hWnd, const LPPOINT lpPoint, PPTOOLTIP_INFO & ti)
	{
		//ENG: Searching a specified HWND
		//RUS: 腮屐 箨噻囗睇?HWND
		mapIter item = m_ToolMap.find(hWnd);
		if (item == m_ToolMap.end())
		{
			//ENG: Specified HWND wasn't found
			//RUS: 雨噻囗睇?HWND 礤 磬殇屙
			return FALSE; 
		} //if

		//ENG: Gets the array with the hotarea's parameters
		//RUS: 项塍鬣屐 爨耨桠 ?镟疣戾蝠囔?泐?麒?珙?箨噻囗钽?铌磬
		arHotArea & hotarea = item->second;
		if ((hotarea.size() == 1) && hotarea[0].rectBounds.IsRectEmpty())
		{
			//ENG: If a bounding rectangle of a hotarea wasn't define
			//RUS: 篷腓 钽疣龛麒忄栝 镳祛筱铍桕 泐?麇?珙睇 礤 铒疱溴脲?
			ti = hotarea[0];
			return TRUE;
		} //if

		POINT ptClient = *lpPoint;
		if (hWnd != m_hParentWnd)
		{
			//ENG: If HWND specified window isn't a parent
			//RUS: 篷腓 HWND 礤 铗眍耔蝰 ?痤滂蝈朦耜铎?铌眢, 蝾 镳孱狃噻箦?觐铕滂磬螓
			::ScreenToClient(hWnd, &ptClient);
		} //if

		CScrollView * pScroll = (CScrollView*)CScrollView::FromHandle(hWnd);
		if (pScroll->IsKindOf(RUNTIME_CLASS(CScrollView))) 
		{
			//ENG: If HWND of CScrollView or derived class then corrects the coordinates
			//RUS: 篷腓 HWND 镳桧噤脲骅?CScrollView 桦?镳铊玮钿眍祗 铗 礤泐 觌囫耋, 蝾 觐痧尻蜩痼屐 觐铕滂磬螓
			CPoint ptScroll = pScroll->GetScrollPosition();
			ptClient.x += ptScroll.x;
			ptClient.y += ptScroll.y;
		} //if

		//ENG: Search a hotarea under the mouse
		//RUS: 腮屐 泐?黧?珙眢 镱?牦瘃铕铎
		arHotArea::iterator iter;
		for (iter = hotarea.begin(); iter != hotarea.end(); ++iter)
		{
			ti = *iter;
			if (ti.rectBounds.PtInRect(ptClient))
			{
				//ENG: A hotarea was found
				//RUS: 穷磬 磬殇屙?
				return TRUE;
			} //if
		} //for

		return FALSE;
	} //End of FindTool

	HWND CPPToolTip::FindToolBarItem(POINT point, PPTOOLTIP_INFO & ti)
	{
		//ENG: Toolbar control was disabled
		//RUS: 暑眚痤朦 玎 镱漶赅珀囔??镟礤??桧耱痼戾眚钼 铗觌屙
		if (!m_wndToolBars.size())
			return NULL;

		//ENG: Gets a window under mouse
		//RUS: 物疱溴?屐 铌眍 镱?牦瘃铕铎
		HWND hWnd = ::WindowFromPoint(point);
		if (NULL != hWnd)
		{
			//ENG: A window was found. Searching a coincidence with toolbar windows
			//RUS: 侮眍 钺磬痼驽眍. 项桉?耦怙噤屙? ?铌磬扈 镟礤脲?桧耱痼戾眚钼
			for (int i = 0; i < (int)m_wndToolBars.size(); i++)
			{
				if (m_wndToolBars[i] == hWnd)
				{
					//ENG: A toolbar under mouse
					//RUS: 相礤朦 桧耱痼戾眚钼 镱?牦瘃铕铎
					CToolBar * pBar = (CToolBar*)CToolBar::FromHandle(hWnd);
					pBar->ScreenToClient(&point);
					//ENG: Gets a item's count of the toolbar
					//RUS: 项塍鬣屐 觐腓麇耱忸 屐屙蝾?镟礤腓 桧耱痼戾眚钼
					int count = pBar->GetCount();
					CRect rect;
					//ENG: Searching an toolbar's item under mouse
					//RUS: 项桉?屐屙蜞 镟礤腓 桧耱痼戾眚钼 磬躅?泐? 镱?牦瘃铕铎
					for (int i = 0; i < count; i++)
					{
						pBar->GetItemRect(i, rect);
						if (rect.PtInRect(point))
						{
							//ENG: Toolbar's item was found
							//RUS: 蓦屐屙?镟礤腓 桧耱痼戾眚钼 钺磬痼驽?
							ti.nIDTool = pBar->GetItemID(i);
							ti.rectBounds = rect;
							ti.nMask = 0;
							ti.sTooltip = m_drawer.GetResCommandPrompt(ti.nIDTool, 1);
							return hWnd;
						} //if
					} //for
					return NULL;
				} //if
			} //for
		} //if
		return NULL;
	} //End of FindToolBarItem


	////////////////////////////////////////////////////////////////////////////////////////////
	// *** public methods ***
	////////////////////////////////////////////////////////////////////////////////////////////

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::AddTool()
	// Registers a tool with the tooltip control.
	//------------------------------------------------------------------
	// Parameters:
	//		pWnd			- Pointer to the window that contains the tool.  
	//		lpszString		- Pointer to the text for the tool. 
	//      dwIdString		- ID of string resource
	//		hIcon			- Handle of the icon
	//		dwIdIcon		- ID of icon resource
	//		szIcon			- Specifies the width and the height, in pixels, of the icon to load.
	//		lpRectBounds	- Pointer to a RECT structure containing coordinates of the tool's bounding rectangle. 
	//						  The coordinates are relative to the upper-left corner of the client area of the window identified by pWnd. 
	//					      NULL if bounding rectangle don't uses for specified window
	//		dwIdTool		- ID of the tool
	//		ti				- Reference to PPTOOLTIP_INFO structure containing the parameters of the tooltip 
	//
	// Remarks:
	//		  A tooltip control can be associated with more than one tool. Call this function to register a tool 
	//		with the tooltip control, so that the information stored in the tooltip is displayed when the cursor is on the tool.
	////////////////////////////////////////////////////////////////////
	void CPPToolTip::AddTool(CWnd * pWnd, DWORD dwIdString, HICON hIcon, LPCRECT lpRectBounds /*= NULL*/, DWORD dwIDTool /*= 0*/)
	{
		CString str;
		str.LoadString(dwIdString);
		AddTool(pWnd, (LPCTSTR)str, hIcon, lpRectBounds, dwIDTool);
	}

	void CPPToolTip::AddTool(CWnd * pWnd, LPCTSTR lpszString, HICON hIcon, LPCRECT lpRectBounds /*= NULL*/, DWORD dwIDTool /*= 0*/)
	{
		CString str;
		str.Format(_T("<table><tr><td><icon handle=0x%X></td><td>%s</td></tr></table>"), 
			hIcon, lpszString);
		AddTool(pWnd, str, lpRectBounds, dwIDTool);
	}

	void CPPToolTip::AddTool(CWnd * pWnd, DWORD dwIdString, DWORD dwIdIcon, CSize & szIcon /* = CSize(0, 0) */, LPCRECT lpRectBounds /*= NULL*/, DWORD dwIDTool /*= 0*/)
	{
		CString str;
		str.LoadString(dwIdString);
		AddTool(pWnd, (LPCTSTR)str, dwIdIcon, szIcon, lpRectBounds, dwIDTool);
	}

	void CPPToolTip::AddTool(CWnd * pWnd, LPCTSTR lpszString, DWORD dwIdIcon, CSize & szIcon /* = CSize(0, 0) */, LPCRECT lpRectBounds /*= NULL*/, DWORD dwIDTool /*= 0*/)
	{
		CString str;
		str.Format(_T("<table><tr><td><icon idres=%d width=%d height=%d></td><td>%s</td></tr></table>"), 
			dwIdIcon, szIcon.cx, szIcon.cy, lpszString);
		AddTool(pWnd, str, lpRectBounds, dwIDTool);
	}

	void CPPToolTip::AddTool(CWnd * pWnd, LPCTSTR lpszString, DWORD dwIdBitmap, COLORREF crMask, CSize & szBitmap /*= CSize(0, 0)*/, LPCRECT lpRectBounds /*= NULL*/, DWORD dwIDTool /*= 0*/)
	{
		CString str;
		str.Format(_T("<table><tr><td><bmp idres=%d mask=0x%X width=%d height=%d></td><td>%s</td></tr></table>"), 
			dwIdBitmap, crMask, szBitmap.cx, szBitmap.cy, lpszString);
		AddTool(pWnd, str, lpRectBounds, dwIDTool);
	}

	void CPPToolTip::AddTool(CWnd * pWnd, DWORD dwIdString, LPCRECT lpRectBounds /* = NULL */, DWORD dwIDTool /* = 0 */)
	{
		CString str;
		str.LoadString(dwIdString);
		AddTool(pWnd, (LPCTSTR)str, lpRectBounds, dwIDTool);
	}

	void CPPToolTip::AddTool(CWnd * pWnd, LPCTSTR lpszString /* = NULL */, LPCRECT lpRectBounds /* = NULL */, DWORD dwIDTool /* = 0 */)
	{
		PPTOOLTIP_INFO ti;

		ti.nIDTool = dwIDTool;
		if (NULL != lpRectBounds)
			ti.rectBounds = *lpRectBounds;
		else 
			ti.rectBounds.SetRectEmpty();
		ti.sTooltip = (CString)lpszString;
		ti.nMask = 0;
		ti.nStyles = 0;
		ti.nDirection = 0;
		ti.nEffect = 0;
		ti.nBehaviour = 0;
		ti.nGranularity = 0;
		ti.crBegin = RGB(0, 0, 0);
		ti.crMid = RGB(0, 0, 0);
		ti.crEnd = RGB(0, 0, 0);

		AddTool(pWnd, ti);
	}

	void CPPToolTip::AddTool(CWnd * pWnd, PPTOOLTIP_INFO & ti)
	{
		TRACE(_T("CPPToolTip::AddTool(hWnd=0x%08X)\n"), pWnd->GetSafeHwnd());
		ASSERT (pWnd);

		//ENG: Gets HWND of a window
		//RUS: 项塍鬣屐 HWND 铌磬
		HWND hWnd = pWnd->GetSafeHwnd();

		//ENG: Searching a specified HWND
		//RUS: 腮屐 箨噻囗睇?HWND
		mapIter item = m_ToolMap.find(hWnd);

		if (item == m_ToolMap.end())
		{
			//ENG: A tooltip for a specified HWND wasn't found therefore create it
			//RUS: 殷腧栾 潆 箨噻囗眍泐 HWND 礤 钺磬痼驽? 镱铎?耦玟噱?邈?
			arHotArea hotarea;
			hotarea.push_back(ti);
			m_ToolMap.insert(std::make_pair(hWnd, hotarea));
			return;
		} //if

		//ENG: Gets parameters of the tooltip
		//RUS: 项塍鬣屐 镟疣戾蝠?蝮腧栾?
		arHotArea & hotarea = item->second;

		//ENG: A tooltip has more one rectangle areas. Check all theirs
		//RUS: 殷腧栾 耦溴疰栩 犷脲?钿眍?镳祛筱铍铋 钺豚耱? 镳钼屦桁 怦艴 桴
		arHotArea::iterator iter;
		for (iter = hotarea.begin(); iter != hotarea.end(); ++iter)
		{
			if (ti.rectBounds == (*iter).rectBounds)
			{
				//ENG: Specified window's rect already exist and so updates him
				//RUS: 雨噻囗睇?镳祛筱铍桕 铌磬 箧?耋耱怏弪, 镱铎?镳铖蝾 钺眍怆屐 邈?镟疣戾蝠?
				*iter = ti;
				return;
			} //if
		} //for

		//ENG: Adds a new tool 
		//RUS: 念徉怆屐 眍恹?桧耱痼戾眚
		hotarea.push_back(ti);
	} //End of AddTool

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::RemoveTool()
	//   Removes the tool specified by pWnd and lpRectBounds from the collection of 
	// tools supported by a tooltip control.
	//------------------------------------------------------------------
	// Parameters:
	//		pWnd			- Pointer to the window that contains the tool.  
	//		lpRectBounds	- Pointer to a RECT structure containing coordinates of the tool's bounding rectangle. 
	//						  The coordinates are relative to the upper-left corner of the client area of the window identified by pWnd. 
	//					      NULL if bounding rectangle don't uses for specified window
	////////////////////////////////////////////////////////////////////
	void CPPToolTip::RemoveTool(CWnd * pWnd, LPCRECT lpRectBounds /* = NULL */)
	{
		TRACE (_T("CPPToolTip::RemoveTool(hWnd=0x%08X)\n"), pWnd->GetSafeHwnd());
		ASSERT(pWnd);

		//ENG: Gets HWND of a window
		//RUS: 项塍鬣屐 HWND 铌磬
		HWND hWnd = pWnd->GetSafeHwnd();

		//ENG: Searching a specified HWND
		//RUS: 腮屐 箨噻囗睇?HWND
		mapIter item = m_ToolMap.find(hWnd);

		if (item == m_ToolMap.end())
		{
			//ENG: Specified HWND wasn't found
			//RUS: 雨噻囗睇?HWND 礤 磬殇屙
			return; 
		} //if

		if (NULL == lpRectBounds)
		{
			//ENG: Removes all tools for the specified window
			//RUS: 愉嚯? 怦?桧耱痼戾眚?潆 箨噻囗眍泐 铌磬
			m_ToolMap.erase(item);
		}
		else
		{
			//ENG: Search the tool to remove
			//RUS: 项桉?桧耱痼戾眚?潆 箐嚯屙?
			arHotArea & hotarea = item->second;
			arHotArea::iterator iter;
			for (iter = hotarea.begin(); iter != hotarea.end(); ++iter)
			{
				if ((*iter).rectBounds == *lpRectBounds)
				{
					//ENG: The tool was found
					//RUS: 软耱痼戾眚 磬殇屙
					if (hotarea.size() > 1)
					{
						//ENG: If the specified window has more one rectangle areas then removes the specified area only
						//RUS: 篷腓 箨噻囗眍?铌眍 耦溴疰栩 犷脲?钿眍?钺豚耱? 蝾 箐嚯屐 蝾朦觐 箨噻囗眢?钺豚耱?
						hotarea.erase(iter);
					}
					else
					{
						//ENG: If the specified window has one rectangle area only then removes the tool for specified window
						//RUS: 篷腓 箨噻囗眍?铌眍 桁邋?蝾朦觐 钿眢 镳祛筱铍簋 钺豚耱? 蝾 箐嚯栩?忮顸 桧耱痼戾眚
						m_ToolMap.erase(item);
					} //if
					return;
				} //if
			} //for
		} //if
	} //End of RemoveTool

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::RemoveAllTools()
	//   Removes all tools from the collection of tools supported by a tooltip control.
	////////////////////////////////////////////////////////////////////
	void CPPToolTip::RemoveAllTools()
	{
		TRACE (_T("CPPToolTip::RemoveAllTools()\n"));

		//ENG: Removes all tools
		//RUS: 愉嚯屐 怦?桧耱痼戾眚?
		if (m_ToolMap.size())
			m_ToolMap.clear();

		//ENG: Removes all toolbars
		//RUS: 愉嚯屐 怦?镟礤腓 桧耱痼戾眚钼
		if (m_wndToolBars.size())
			m_wndToolBars.clear();
	} //End of RemoveAllTools

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::AddToolBar()
	// Registers a toolbar to the tooltip control.
	//------------------------------------------------------------------
	// Parameters:
	//		pBar			- Pointer to the toolbar window.  
	////////////////////////////////////////////////////////////////////
	void CPPToolTip::AddToolBar(CToolBar * pBar)
	{
		TRACE (_T("CPPToolTip::AddToolBar(hWnd=0x%08X)\n"), pBar->GetSafeHwnd());
		ASSERT(pBar);

		//ENG: Gets HWND toolbar's window
		//RUS: 项塍鬣屐 HWND 铌磬 镟礤腓 桧耱痼戾眚钼
		HWND hWnd = pBar->GetSafeHwnd();

		//ENG: Searching a clone of a toolbar
		//RUS: 项桉?潴犭桕囹?箨噻囗眍?镟礤腓 桧耱痼戾眚钼
		arToolBarWnd::iterator iter;
		for (iter = m_wndToolBars.begin(); iter != m_wndToolBars.end(); ++iter)
		{
			if (*iter == hWnd)
			{
				//ENG: A clone was found
				//RUS: 捏犭桕囹 磬殇屙
				return;
			} //if
		} //for

		//ENG: Stores HWND toolbar's window
		//RUS: 青镱扈磬屐 HWND 铌磬 镟礤腓 桧耱痼戾眚钼
		m_wndToolBars.push_back(hWnd);

		//ENG: Disables a standard tooltip for the specified toolbar
		//RUS: 青镳妁噱?耱囗溧痱睇?镱漶赅珀?潆 箨噻囗铋 镟礤腓 桧耱痼戾眚钼
		DWORD dwStyles = pBar->GetBarStyle();
		dwStyles &= ~CBRS_TOOLTIPS;
		pBar->SetBarStyle(dwStyles);
	} //End of AddToolBar


	BOOL CPPToolTip::GetToolInfo(PPTOOLTIP_INFO & ti, CWnd * pWnd, LPCRECT lpRectBounds /* = NULL */)
	{
		ASSERT(pWnd);

		//ENG: Gets HWND of a window
		//RUS: 项塍鬣屐 HWND 铌磬
		HWND hWnd = pWnd->GetSafeHwnd();	
		//ENG: Searching a specified HWND
		//RUS: 腮屐 箨噻囗睇?HWND
		mapIter item = m_ToolMap.find(hWnd);	
		if (item == m_ToolMap.end())
		{
			//ENG: Specified HWND wasn't found
			//RUS: 雨噻囗睇?HWND 礤 磬殇屙
			return FALSE; 
		} //if

		//ENG: Gets parameters of the tooltip
		//RUS: 项塍鬣屐 镟疣戾蝠?蝮腧栾?
		arHotArea & hotarea = item->second;

		//ENG: A tooltip has more one rectangle areas. Check all theirs
		//RUS: 殷腧栾 耦溴疰栩 犷脲?钿眍?镳祛筱铍铋 钺豚耱? 镳钼屦桁 怦艴 桴
		arHotArea::iterator iter;
		for (iter = hotarea.begin(); iter != hotarea.end(); ++iter)
		{
			if (lpRectBounds == (*iter).rectBounds)
			{
				//ENG: Specified window's rect already exist and so updates him
				//RUS: 雨噻囗睇?镳祛筱铍桕 铌磬 箧?耋耱怏弪, 镱铎?镳铖蝾 钺眍怆屐 邈?镟疣戾蝠?
				ti = *iter;
				return TRUE ;
			} //if
		} //for

		return FALSE;
	}

	BOOL CPPToolTip::GetToolInfo(PPTOOLTIP_INFO & ti, CWnd * pWnd, DWORD dwIDTool /* = 0 */)
	{
		ASSERT(pWnd);

		//ENG: Gets HWND of a window
		//RUS: 项塍鬣屐 HWND 铌磬
		HWND hWnd = pWnd->GetSafeHwnd();	
		//ENG: Searching a specified HWND
		//RUS: 腮屐 箨噻囗睇?HWND
		mapIter item = m_ToolMap.find(hWnd);	
		if (item == m_ToolMap.end())
		{
			//ENG: Specified HWND wasn't found
			//RUS: 雨噻囗睇?HWND 礤 磬殇屙
			return FALSE; 
		} //if

		//ENG: Gets parameters of the tooltip
		//RUS: 项塍鬣屐 镟疣戾蝠?蝮腧栾?
		arHotArea & hotarea = item->second;

		arHotArea::iterator iter;
		for (iter = hotarea.begin(); iter != hotarea.end(); ++iter)
		{
			if (dwIDTool == (*iter).nIDTool)
			{
				ti = *iter;
				return TRUE ;
			} //if
		} //for

		return FALSE;
	}

	void CPPToolTip::UpdateTipText(LPCTSTR lpszText, CWnd * pWnd, DWORD dwIDTool /* = 0 */)
	{
		PPTOOLTIP_INFO ti;
		if (GetToolInfo(ti, pWnd, dwIDTool))
		{
			ti.sTooltip = lpszText;
			AddTool(pWnd, ti);
		}
	}

	void CPPToolTip::DelTool(CWnd * pWnd, DWORD dwIDTool)
	{
		PPTOOLTIP_INFO ti;
		if (GetToolInfo(ti, pWnd, dwIDTool))
		{
			RemoveTool(pWnd, ti.rectBounds);
		}
	}

	void CPPToolTip::SetToolRect(CWnd * pWnd, DWORD dwIDTool, LPCRECT lpRectBounds)
	{
		PPTOOLTIP_INFO ti;
		if (GetToolInfo(ti, pWnd, dwIDTool))
		{
			ti.rectBounds = *lpRectBounds;
			AddTool(pWnd, ti);
		}
	}

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::EnableHyperlink()
	// Enables redrawing hyperlinks and hot areas.
	////////////////////////////////////////////////////////////////////
	void CPPToolTip::EnableHyperlink(BOOL bEnable /* = TRUE */)
	{
		m_bHyperlinkEnabled = bEnable;
	} //End of EnableHyperlink

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::SetCallbackHyperlink()
	//   Sets the callback message that will be sent to the specified window 
	// if user clicks a hyperlink or hotareas with a msg parameter.
	//------------------------------------------------------------------
	// Parameters:
	//		hWnd			- Handle of the window that will receive the callback message.
	//						  Pass NULL to remove any previously specified callback message.
	//		nMessage		- Callback message to send to window.
	//		lParam			- A 32 bits user specified value that will be passed to the callback function.
	//
	// Remarks:
	//    The callback function must be in the form:
	//  LRESULT On_MenuCallback(WPARAM wParam, LPARAM lParam)
	//		wParam			- Pointer to the string specified as parameter in <a msg=> tag.
	//		lParam			- The 32 bits user specified value.
	////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetCallbackHyperlink(HWND hWnd, UINT nMessage, LPARAM lParam /* = 0 */)
	{
		TRACE(_T("CPPToolTip::SetCallbackHyperlink()\n"));

		m_drawer.SetCallbackHyperlink(hWnd, nMessage, lParam);
	} //End of SetCallbackHyperlink

	/////////////////////////////////////////////////////////////////////
	// CPPToolTip::SetNotify()
	// This function sets or removes the notification messages from the control before display.
	//-------------------------------------------------------------------
	// Parameters:
	//		bParentNotify	- If TRUE the tooltip will be send the notification to parent window
	//						  Else the notification will not send
	//		hWnd			- If non-NULL the tooltip will be send the notification to specified window
	//						  Else the notification will not send
	///////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetNotify(BOOL bParentNotify /* = TRUE */)
	{
		HWND hWnd = NULL;

		if (bParentNotify)
			hWnd = m_hParentWnd;

		SetNotify(hWnd);
	} //End of SetNotify

	void CPPToolTip::SetNotify(HWND hWnd)
	{
		TRACE(_T("CPPToolTip::SetNotify\n"));

		m_hNotifyWnd = hWnd;
	} //End of SetNotify

	/////////////////////////////////////////////////////////////////////////////
	//  CPPToolTip::SetSize()
	//    Sets the specified size
	//---------------------------------------------------------------------------
	//  Parameters :
	//		nSizeIndex		- index of the size. This parameter can be one 
	//						  of the following values:
	//							PPTTSZ_ROUNDED_CX - The width of the ellipse used 
	//												to draw the rounded corners, in logical units.
	//							PPTTSZ_ROUNDED_CY - The height of the ellipse used 
	//												to draw the rounded corners, in logical units.
	//							PPTTSZ_MARGIN_CX  - The left and right margins of the tooltip's 
	//												text from the tooltip's edges. 
	//							PPTTSZ_MARGIN_CY  - The top and bottom margins of the tooltip's 
	//												text from the tooltip's edges.
	//							PPTTSZ_WIDTH_ANCHOR - The width of the tooltip's anchor
	//							PPTTSZ_HEIGHT_ANCHOR - The height of the tooltip's anchor 
	//							PPTTSZ_MARGIN_ANCHOR - The margin of the tooltip's anchor from 
	//												   his edge.
	//							PPTTSZ_OFFSET_ANCHOR_CX - The horizontal offset of the tooltip's anchor
	//													  from the hot spot of a cursor
	//							PPTTSZ_OFFSET_ANCHOR_CY - The vertical offset of the tooltip's anchor
	//													  from the hot spot of a cursor
	//		nValue			- size's value
	/////////////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetSize(int nSizeIndex, int nValue)
	{
		TRACE(_T("CPPToolTip::SetSize(nSizeIndex = %d, nValue = %d)\n"), nSizeIndex, nValue);
		if (nSizeIndex >= PPTTSZ_MAX_SIZES)
			return;

		m_nSizes [nSizeIndex] = nValue;
	} //End of SetSize

	/////////////////////////////////////////////////////////////////////////////
	//  CPPTootTip::GetSize()
	//    Gets the specified size
	//---------------------------------------------------------------------------
	//  Parameters :
	//		nSizeIndex		- An index of the sizes. See CPPToolTip::SetSize for a 
	//						  description of the valid values.
	//  Returns :
	//		size's value
	//
	/////////////////////////////////////////////////////////////////////////////
	int CPPToolTip::GetSize(int nSizeIndex)
	{
		TRACE(_T("CPPToolTip::GetSize(nSizeIndex = %d)\n"), nSizeIndex);
		if (nSizeIndex >= PPTTSZ_MAX_SIZES)
			return 0;

		return m_nSizes [nSizeIndex];
	} //End of GetSize

	/////////////////////////////////////////////////////////////////////////////
	//  CPPToolTip::SetDefaultSizes()
	//    Sets all sizes to default values
	//---------------------------------------------------------------------------
	//  Parameters:
	//		bBalloonSize	- If TRUE all sizes will be sets for balloon tooltip
	//						  otherwise tooltip will look as standard 
	/////////////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetDefaultSizes(BOOL bBalloonSize /* = TRUE */)
	{
		TRACE(_T("CPPToolTip::SetDefaultSizes()\n"));

		if (bBalloonSize)
		{
			SetSize(PPTTSZ_ROUNDED_CX, 16);
			SetSize(PPTTSZ_ROUNDED_CY, 16);
			SetSize(PPTTSZ_MARGIN_CX, 12);
			SetSize(PPTTSZ_MARGIN_CY, 12);
			SetSize(PPTTSZ_WIDTH_ANCHOR, 12);
			SetSize(PPTTSZ_HEIGHT_ANCHOR, 16);
			SetSize(PPTTSZ_MARGIN_ANCHOR, 16);
			SetSize(PPTTSZ_OFFSET_ANCHOR_CX, 0);
			SetSize(PPTTSZ_OFFSET_ANCHOR_CY, 0);
		}
		else
		{
			SetSize(PPTTSZ_ROUNDED_CX, 0);
			SetSize(PPTTSZ_ROUNDED_CY, 0);
			SetSize(PPTTSZ_MARGIN_CX, 3);
			SetSize(PPTTSZ_MARGIN_CY, 1);
			SetSize(PPTTSZ_WIDTH_ANCHOR, 0);
			SetSize(PPTTSZ_HEIGHT_ANCHOR, 0);
			SetSize(PPTTSZ_MARGIN_ANCHOR, 0);
			SetSize(PPTTSZ_OFFSET_ANCHOR_CX, 0);
			SetSize(PPTTSZ_OFFSET_ANCHOR_CY, 0);
		} //if
	} //End of SetDefaultSizes

	/////////////////////////////////////////////////////////////////////////////
	// CPPToolTip::SetColorBk()
	//   Sets background's colors 
	//---------------------------------------------------------------------------
	//  Parameters:
	//		color			- A solid color for background's effect 
	//		clrBegin		- A begin color for background's effect
	//		clrMid			- A middle color for background's effect
	//		clrEnd			- A end color for background's effect
	/////////////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetColorBk(COLORREF color)
	{
		SetColorBk(color, color, color);
	} //End of SetColorBk

	void CPPToolTip::SetColorBk(COLORREF clrBegin, COLORREF clrEnd)
	{
		SetColorBk(clrBegin, clrBegin, clrEnd);
	} //End of SetColorBk

	void CPPToolTip::SetColorBk(COLORREF clrBegin, COLORREF clrMid, COLORREF clrEnd)
	{
		m_clrBeginBk = clrBegin;
		m_clrMidBk = clrMid;
		m_clrEndBk = clrEnd;
	} //End of SetColorBk

	/////////////////////////////////////////////////////////////////////////////
	// CPPToolTip::SetEffectBk()
	//   Sets a background's effect 
	//---------------------------------------------------------------------------
	//  Parameters:
	//		dwEffect		- A background's effect 
	//		nGranularity	- Adds an uniform noise to the effect. 
	//						  A good value is from 5 to 20; 0 to disable the effect. 
	//						  The noise has a positive effect because it hides the palette steps.
	/////////////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetEffectBk(DWORD dwEffect, BYTE nGranularity /* = 5 */)
	{
		m_dwEffectBk = dwEffect;
		m_nGranularity = nGranularity;
	} //End of SetEffectBk

	/////////////////////////////////////////////////////////////////////////////
	// CPPToolTip::SetBehaviour()
	//   Sets a tooltip's behaviour 
	//---------------------------------------------------------------------------
	//  Parameters:
	//		dwBehaviour		- A tooltip's behaviour. 0 for normal tooltip without 
	//						  specific behaviours. This parameter can be any combination 
	//						  of CPPToolTip behaviours:
	//							PPTOOLTIP_MULTIPLE_SHOW		- Multiple show for single control
	//							PPTOOLTIP_TRACKING_MOUSE	- Tracking for mouse
	//							PPTOOLTIP_CLOSE_LEAVEWND	- Close tooltip if mouse leave the control
	//							PPTOOLTIP_NOCLOSE_OVER		- No close tooltip if mouse over him
	//							PPTOOLTIP_DISABLE_AUTOPOP	- Disables autopop tooltip from timer
	/////////////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetBehaviour(DWORD dwBehaviour /* = 0 */)
	{
		m_dwBehaviour = dwBehaviour;
	} //End of SetBehaviour

	/////////////////////////////////////////////////////////////////////////////
	// CPPToolTip::GetBehaviour()
	//   Gets a tooltip's behaviour 
	//---------------------------------------------------------------------------
	// Return value:
	//		A tooltip's behaviour. See CPPToolTip::SetBehaviour for a description of the 
	//	valid values.
	/////////////////////////////////////////////////////////////////////////////
	DWORD CPPToolTip::GetBehaviour()
	{
		return m_dwBehaviour;
	} //End of GetBehaviour

	/////////////////////////////////////////////////////////////////////
	//  CPPToolTip::SetDelayTime()
	//   Call this function to set the delay time for a tooltip control. 
	// The delay time is the length of time the cursor must remain on a tool 
	// before the tooltip window appears. The default delay time is 500 milliseconds.
	//-------------------------------------------------------------------
	// Parameters:
	//		dwDuration		- Flag that specifies which duration value will be retrieved. 
	//						  This parameter can be one of the following values:
	//							PPTOOLTIP_TIME_AUTOPOP  - Retrieve the length of time the tooltip 
	//													  window remains visible if the pointer is 
	//													  stationary within a tool's bounding rectangle. 
	//							PPTOOLTIP_TIME_INITIAL  - Retrieve the length of time the pointer 
	//			 										  must remain stationary within a tool's bounding 
	//													  rectangle before the tool tip window appears. 
	//							PPTOOLTIP_TIME_FADEIN	- Retrieve the length of time for each step of
	//													  fade-in effect
	//							PPTOOLTIP_TIME_FADEOUT	- Retrieve the length of time for each step of
	//													  fade-out effect
	//							PPTOOLTIP_TIME_ANIMATION  Retrieve the speed for the animation
	//						  For compatibility with 1.x versions of CPPToolTip a following values
	//						  are available also:
	//							TTDT_AUTOPOP			- Same PPTOOLTIP_TIME_AUTOPOP 
	//							TTDT_INITIAL			- Same PPTOOLTIP_TIME_INITIAL 
	//		nTime			- The specified delay time, in milliseconds.
	/////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetDelayTime(DWORD dwDuration, DWORD dwTime)
	{
		switch (dwDuration)
		{
		case PPTOOLTIP_TIME_AUTOPOP:
			m_dwTimeAutoPop = dwTime;
			break;
		case PPTOOLTIP_TIME_INITIAL:
			m_dwTimeInitial = dwTime;
			break;
		case PPTOOLTIP_TIME_FADEIN:
			m_dwTimeFadeIn = dwTime;
			break;
		case PPTOOLTIP_TIME_FADEOUT:
			m_dwTimeFadeOut = dwTime;
			break;
		case PPTOOLTIP_TIME_ANIMATION:
			KillTimer(TIMER_ANIMATION);
			if (dwTime)
				SetTimer(TIMER_ANIMATION, dwTime, NULL);
			break;
		}
	} //End of SetDelayTime

	/////////////////////////////////////////////////////////////////////
	// CPPToolTip::GetDelayTime()
	// Retrieves the initial, pop-up, and reshow durations currently set 
	// for a CPPToolTip control
	//-------------------------------------------------------------------
	// Parameters:
	//		dwDuration		- Flag that specifies which duration value will be retrieved. 
	//						  See CPPToolTip::SetDelayTime for a description of the valid values. 
	// Return value:
	//	The specified delay time, in milliseconds
	///////////////////////////////////////////////////////////////////////
	DWORD CPPToolTip::GetDelayTime(DWORD dwDuration) const
	{
		DWORD dwTime = 0;
		switch (dwDuration)
		{
		case PPTOOLTIP_TIME_AUTOPOP:
			dwTime = m_dwTimeAutoPop;
			break;
		case PPTOOLTIP_TIME_INITIAL:
			dwTime = m_dwTimeInitial;
			break;
		case PPTOOLTIP_TIME_FADEIN:
			dwTime = m_dwTimeFadeIn;
			break;
		case PPTOOLTIP_TIME_FADEOUT:
			dwTime = m_dwTimeFadeOut;
			break;
		}

		return dwTime;
	} //End of GetDelayTime

	/////////////////////////////////////////////////////////////////////////////
	//  CPPToolTip::SetDirection()
	//    Sets a placement of the tooltip's anchor
	//---------------------------------------------------------------------------
	//  Parameters :
	//		dwDirection		- A placement of the tooltip's anchor. This parameter 
	//					      can be one of the following values:
	//							PPTOOLTIP_TOPEDGE_LEFT			- A left corner of the top edge
	//							PPTOOLTIP_TOPEDGE_RIGHT			- A right corner of the top edge
	//							PPTOOLTIP_TOPEDGE_CENTER		- By center of the top edge
	//							PPTOOLTIP_BOTTOMEDGE_LEFT		- A left corner of the bottom edge
	//							PPTOOLTIP_BOTTOMEDGE_RIGHT		- A right corner of the bottom edge
	//							PPTOOLTIP_BOTTOMEDGE_CENTER		- By center of the bottom edge
	//							PPTOOLTIP_LEFTEDGE_TOP			- A top corner of the left edge
	//							PPTOOLTIP_LEFTEDGE_BOTTOM		- A bottom corner of the left edge
	//							PPTOOLTIP_LEFTEDGE_VCENTER		- By center of the left edge
	//							PPTOOLTIP_RIGHTEDGE_TOP			- A top corner of the right edge
	//							PPTOOLTIP_RIGHTEDGE_BOTTOM		- A bottom corner of the right edge
	//							PPTOOLTIP_RIGHTEDGE_VCENTER		- By center of the right edge
	//						  For compatibility with 1.x versions of CPPToolTip a following values
	//						  are available also:
	//							PPTOOLTIP_LEFT_TOP				- Same PPTOOLTIP_TOPEDGE_LEFT
	//							PPTOOLTIP_RIGHT_TOP				- Same PPTOOLTIP_TOPEDGE_RIGHT
	//							PPTOOLTIP_LEFT_BOTTOM			- Same PPTOOLTIP_BOTTOMEDGE_LEFT
	//							PPTOOLTIP_RIGHT_BOTTOM			- Same PPTOOLTIP_BOTTOMEDGE_RIGHT
	/////////////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetDirection(DWORD dwDirection /* = PPTOOLTIP_BOTTOMEDGE_LEFT */)
	{
		TRACE(_T("CPPToolTip::SetDirection(nDirection = %d)\n"), dwDirection);

		m_dwDirection = dwDirection;
	} //End of SetDirection	

	/////////////////////////////////////////////////////////////////////////////
	//  CPPToolTip::GetDirection()
	//    Gets a placement of the tooltip's anchor
	//---------------------------------------------------------------------------
	//  Returns :
	//	  A placement of the tooltip's anchor. See CPPToolTip::SetDirection for a description of 
	//	the valid values.
	/////////////////////////////////////////////////////////////////////////////
	DWORD CPPToolTip::GetDirection()
	{
		TRACE(_T("CPPToolTip::GetDirection()\n"));

		return m_dwDirection;
	} //End of GetDirection

	/////////////////////////////////////////////////////////////////////////////
	//  CPPToolTip::SetTextStyles()
	//    Applies a CSS-like style for the tooltip's HTML
	//---------------------------------------------------------------------------
	//  Parameters:
	//		lpszStyleName	- Pointer to a null-terminated string that specifies
	//						  a name of CSS style
	//		lpszStyleValue  - Pointer to a null-terminated string that specifies 
	//						  CSS-lite style for drawing a tooltip text.
	/////////////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetTextStyle(LPCTSTR lpszStyleName, LPCTSTR lpszStyleValue)
	{
		m_drawer.SetTextStyle(lpszStyleName, lpszStyleValue);
	}

	/////////////////////////////////////////////////////////////////////////////
	//  CPPToolTip::SetCssStyles()
	//    Applies a CSS-like styles for the tooltip's HTML
	//---------------------------------------------------------------------------
	//  Parameters:
	//		lpszCssStyles	- Pointer to a null-terminated string that specifies 
	//						  CSS-lite styles for drawing a tooltip text.
	/////////////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetCssStyles(LPCTSTR lpszCssStyles /* = NULL */)
	{
		m_drawer.SetCssStyles(lpszCssStyles);
	} //End of SetCssStyles

	///////////////////////////////////////////////////////////////////////////// 
	//  CPPToolTip::SetCssStyles() 
	//    Applies a CSS-like styles for the tooltip's HTML 
	//--------------------------------------------------------------------------- 
	//  Parameters: 
	//      dwIdCssStyle    - ID of string resource 
	//      lpszPathDll		- 
	///////////////////////////////////////////////////////////////////////////// 
	void CPPToolTip::SetCssStyles(DWORD dwIdCssStyle, LPCTSTR lpszPathDll /* = NULL */) 
	{ 
		m_drawer.SetCssStyles(dwIdCssStyle, lpszPathDll); 
	} //End of SetCssStyles

	/////////////////////////////////////////////////////////////////////////////
	//  CPPToolTip::GetCssStyles()
	//    Applies a CSS-like styles for the tooltip's HTML
	//---------------------------------------------------------------------------
	//  Return value:
	//		Pointer to a null-terminated string that specifies CSS-lite styles 
	//  for drawing a tooltip text.
	/////////////////////////////////////////////////////////////////////////////
	LPCTSTR CPPToolTip::GetCssStyles()
	{
		return m_drawer.GetCssStyles();
	} //End of GetCssStyles

	/////////////////////////////////////////////////////////////////////////////
	//  CPPToolTip::SetDebugMode()
	//    Sets a debug mode. In this mode tooltip will display for any control
	// and will contain debug info about control.
	//---------------------------------------------------------------------------
	//  Parameters:
	//		bDebug			- TRUE set a debug mode.
	/////////////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetDebugMode(BOOL bDebug /* = TRUE */)
	{
		m_bDebugMode = bDebug;
	} //End of SetDebugMode

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::ShowHelpTooltip()
	// Shows the help tooltip in any place of screen.
	//------------------------------------------------------------------
	// Parameters:
	//		pt				- Pointer to a POINT structure that receives the screen coordinates of the tooltip's anchor  
	//		lpszString		- Pointer to the text for the help tooltip. 
	//      dwIdString		- ID of string resource
	//		hIcon			- Handle of the icon
	//		dwIdIcon		- ID of icon resource
	//		szIcon			- Specifies the width and the height, in pixels, of the icon to load.
	//		ti				- Reference to PPTOOLTIP_INFO structure containing the parameters of the tooltip 
	////////////////////////////////////////////////////////////////////
	void CPPToolTip::ShowHelpTooltip(LPPOINT pt, DWORD dwIdText, HICON hIcon /* = NULL */)
	{
		CString str;
		str.LoadString(dwIdText);
		ShowHelpTooltip(pt, (LPCTSTR)str, hIcon);
	} //End ShowHelpTooltip

	void CPPToolTip::ShowHelpTooltip(LPPOINT pt, DWORD dwIdText, DWORD dwIdIcon, CSize & szIcon /* = CSize(0, 0) */)
	{
		CString str;
		str.LoadString(dwIdText);
		ShowHelpTooltip(pt, (LPCTSTR)str, dwIdIcon, szIcon);
	} //End ShowHelpTooltip

	void CPPToolTip::ShowHelpTooltip(LPPOINT pt, LPCTSTR lpszString, HICON hIcon /* = NULL */)
	{
		PPTOOLTIP_INFO ti;
		if (NULL == hIcon)
		{
			ti.sTooltip = (CString)lpszString;
		}
		else
		{
			ti.sTooltip.Format(_T("<table><tr><td><icon handle=0x%X></td><td>%s</td></tr></table>"), 
				hIcon, lpszString);
		} //if

		ti.nMask = 0;
		ShowHelpTooltip(pt, ti);
	} //End ShowHelpTooltip

	void CPPToolTip::ShowHelpTooltip(LPPOINT pt, LPCTSTR lpszString, DWORD dwIdIcon, CSize & szIcon /* = CSize(0, 0) */)
	{
		CString str;
		str.Format(_T("<table><tr><td><icon idres=%d width=%d height=%d></td><td>%s</td></tr></table>"), 
			dwIdIcon, szIcon.cx, szIcon.cy, lpszString);
		ShowHelpTooltip(pt, (LPCTSTR)str);
	} //End ShowHelpTooltip

	void CPPToolTip::ShowHelpTooltip(LPPOINT pt, PPTOOLTIP_INFO & ti)
	{
		TRACE(_T("CPPToolTip::ShowHelpTooltip\n"));

		m_ptOriginal = CPoint(pt->x, pt->y);
		ti.nBehaviour = m_dwBehaviour | PPTOOLTIP_DISABLE_AUTOPOP;
		ti.nMask = PPTOOLTIP_MASK_BEHAVIOUR;
		SetNewTooltip(NULL, ti, FALSE, PPTOOLTIP_HELP);
	} //End ShowHelpTooltip

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::SetBorder()
	// Sets a border of the tooltip.
	//------------------------------------------------------------------
	// Parameters:
	//		color			- Color of the tooltip's border
	//		hbr				- Brush for drawing tooltip's border
	//      nWidth			- A width of the brush
	//		nHeight			- A height of the brush
	////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetBorder(COLORREF color, int nWidth /* = 1 */, int nHeight /* = 1 */)
	{
		HBRUSH hbr = ::CreateSolidBrush(color);
		SetBorder(hbr, nWidth, nHeight);
	} //End of SetBorder

	void CPPToolTip::SetBorder(HBRUSH hbr, int nWidth /* = 1 */, int nHeight /* = 1 */)
	{
		HideBorder();
		if (nWidth && nHeight && (NULL != hbr))
		{
			m_hbrBorder = hbr;
			m_szBorder.cx = nWidth;
			m_szBorder.cy = nHeight;
		} //if
	} //End of SetBorder

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::HideBorder()
	// Hides border of the tooltip.
	////////////////////////////////////////////////////////////////////
	void CPPToolTip::HideBorder()
	{
		if (NULL != m_hbrBorder)
		{
			::DeleteObject(m_hbrBorder);
			m_hbrBorder = NULL;
		} //if
		m_szBorder.cx = 0;
		m_szBorder.cy = 0;
	} //End of HideBorder

	////////////////////////////////////////////////////////////////////////////////
	// Begin of the menu methods block. Build-in support for menu
#ifdef PPTOOLTIP_USE_MENU
	//////////////////
	// Need to handle WM_ENTERIDLE to cancel the tip if the user 
	// moved the mouse off the popup menu. For main menus, Windows 
	// will send a WM_MENUSELECT message for the parent menu when 
	// this happens, but for context menus there's no other way to 
	// know the user moved the mouse off the menu.
	//
	void CPPToolTip::OnEnterIdle(UINT nWhy, CWnd* pWho)
	{
		if ((MSGF_MENU == nWhy))
		{
			if (m_nTooltipType == PPTOOLTIP_MENU)
			{
				if (PPTOOLTIP_STATE_SHOWN == m_nTooltipState)
				{
					CPoint pt;
					GetCursorPos(&pt);
					if (pWho->GetSafeHwnd() != ::WindowFromPoint(pt)) 
					{
						HideTooltip();
					} //if
				} //if
			} //if
		} //if
	} //End of OnEnterIdle

	void CPPToolTip::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSubMenu)
	{
		if (((nFlags & 0xFFFF) == 0xFFFF) || (nFlags & MF_POPUP) || (nFlags & MF_SEPARATOR))
		{
			//HideTooltip();
			Pop();
		} 
		else if (nItemID && hSubMenu) 
		{
			HWND hwndMenu = GetRunningMenuWnd(); //CWnd::WindowFromPoint(pt);
			if (NULL != hwndMenu)
			{
				CRect rcMenu;
				::GetWindowRect(hwndMenu, rcMenu); // whole menu rect

				// find Item Rectangle and position
				int count = ::GetMenuItemCount(hSubMenu);
				int cy = rcMenu.top + GetSystemMetrics(SM_CYEDGE) + 1;
				for(int nItem = 0; nItem < count; nItem++) 
				{
					CRect rect;
					::GetMenuItemRect(m_hParentWnd, hSubMenu, nItem, &rect);
					if(nItemID == ::GetMenuItemID(hSubMenu, nItem)) 
					{
						UINT nState = GetMenuState(hSubMenu, nItemID, MF_BYCOMMAND);
						CString str;
						if (MF_DISABLED & nState)
							str = m_drawer.GetResCommandPrompt(nItemID, 2); //String for disabled item
						else
							str = m_drawer.GetResCommandPrompt(nItemID, 0);

						CPoint pt;
						// found menu item: adjust rectangle to right and down
						pt.x = rcMenu.left;
						pt.y = cy;
						if (m_dwMenuToolPos & PPTOOLTIP_MENU_CENTER)
							pt.x += rect.Width() / 2;
						else if (m_dwMenuToolPos & PPTOOLTIP_MENU_RIGHT)
							pt.x += rect.Width();

						if (m_dwMenuToolPos & PPTOOLTIP_MENU_VCENTER)
							pt.y += rect.Height() / 2;
						else if (m_dwMenuToolPos & PPTOOLTIP_MENU_BOTTOM)
							pt.y += rect.Height();

						PPTOOLTIP_INFO ti;
						ti.rectBounds = rect;
						ti.nMask = 0;
						ti.sTooltip = str;
						m_nNextTooltipType = PPTOOLTIP_MENU;
						m_ptOriginal = pt;
						SetNewTooltip(hwndMenu, ti, TRUE, PPTOOLTIP_MENU);

						return;
					} //if
					cy += rect.Height(); // add height
				} //for
			} //if
			//ENG: Menu item was not found
			//RUS: 蓦屐屙?戾睨 礤 磬殇屙.
			Pop();
		} //if
	} //End of OnMenuSelect

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::GetRunningMenuWnd()
	// Get running menu window.
	////////////////////////////////////////////////////////////////////
	HWND CPPToolTip::GetRunningMenuWnd()
	{
		HWND hwnd = NULL;
		EnumWindows(MyEnumProc,(LPARAM)&hwnd);
		return hwnd;
	} //End of GetRunningMenuWnd

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::MenuToolPosition()
	// Sets a position of the tooltip's anchor about menu item.
	//------------------------------------------------------------------
	// Parameters:
	//		nPos			- A tooltip's position. This parameter can be any combination 
	//						  of single horizontal value and single vertical value of CPPToolTip:
	//							--- Horizontal position ---
	//							PPTOOLTIP_MENU_LEFT		0x00
	//							PPTOOLTIP_MENU_RIGHT	0x01
	//							PPTOOLTIP_MENU_CENTER	0x02
	//							--- Vertical position ---
	//							PPTOOLTIP_MENU_TOP		0x00
	//							PPTOOLTIP_MENU_BOTTOM	0x10
	//							PPTOOLTIP_MENU_VCENTER  0x20
	////////////////////////////////////////////////////////////////////
	void CPPToolTip::MenuToolPosition(DWORD nPos /* = PPTOOLTIP_MENU_LEFT | PPTOOLTIP_MENU_TOP */)
	{
		m_dwMenuToolPos = nPos;
	} //End of MenuToolPosition

	// End of menu methods block
	///////////////////////////////////////////////////////////
#endif //PPTOOLTIP_USE_MENU

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::EnableEscapeSequences()
	//		Enables the escape sequences. If the escape sequences was disabled
	//	HTML-lite compiler will ignore the codes less then 0x20 (such \n, \r, \t).
	////////////////////////////////////////////////////////////////////
	void CPPToolTip::EnableEscapeSequences(BOOL bEnable)
	{
		m_drawer.EnableEscapeSequences(bEnable);
	} //End of EnableEscapeSequences

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::SetImageList()
	//		Sets an image list for using it into the HTML string with <ilst> tag.
	//------------------------------------------------------------------
	// Parameters:
	//		nIdBitmap		- Resource IDs of the bitmap to be associated with the image list.
	//		hBitmap			- Handle of the bitmap to be associated with the image list.
	//      cx				- Dimensions of each image, in pixels.
	//		cy				- Dimensions of each image, in pixels.
	//		nCount			- The number of images in the image list
	//		crMask			- Color used to generate a mask. Each pixel of this color in 
	//						  the specified bitmap is changed to transparent, and the 
	//						  corresponding bit in the mask is set to one.
	////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetImageList(UINT nIdBitmap, int cx, int cy, int nCount, COLORREF crMask /* = RGB(255, 0, 255) */)
	{
		m_drawer.SetImageList(nIdBitmap, cx, cy, nCount, crMask);
	} //End of SetImageList

	void CPPToolTip::SetImageList(HBITMAP hBitmap, int cx, int cy, int nCount, COLORREF crMask /* = RGB(255, 0, 255) */)
	{
		m_drawer.SetImageList(hBitmap, cx, cy, nCount, crMask);
	} //End of SetImageList

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::SetTransparency()
	//		Sets a transparency of the tooltip.
	//------------------------------------------------------------------
	// Parameters:
	//		nTransparency	- A transparency value to be used on the tooltip. 
	//						  The default 0 assumes that your tooltip is opaque and 0xFF (255) 
	//						  for full transparency of the tooltip.
	////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetTransparency(BYTE nTransparency /* = 0 */) 
	{
		if (nTransparency <= PERCENT_MAX_TRANSPARENCY)
			m_nTransparency = nTransparency;
	} //End of SetTransparency

	////////////////////////////////////////////////////////////////////
	// CPPToolTip::SetTooltipShadow()
	//		Sets a tooltip's shadow.
	//------------------------------------------------------------------
	// Parameters:
	//		nOffsetX, 
	//		nOffsetY		- The offsets of the tooltip's shadow from the tooltip's window.
	//		nDarkenPercent	- So far as colors under the shadow will be darken (0 - 100)
	//      bGradient		- TRUE to use a gradient shadow.
	//		nDepthX,
	//		nDepthY			- The gradient depths of the tooltip's shadow.
	////////////////////////////////////////////////////////////////////
	void CPPToolTip::SetTooltipShadow(int nOffsetX, int nOffsetY, BYTE nDarkenPercent /* = 50 */, 
		BOOL bGradient /* = TRUE */, int nDepthX /* = 7 */, int nDepthY /* = 7 */)
	{
		m_szOffsetShadow.cx = nOffsetX;
		m_szOffsetShadow.cy = nOffsetY;
		m_szDepthShadow.cx = nDepthX;
		m_szDepthShadow.cy = nDepthY;
		m_nDarkenShadow = min(100, nDarkenPercent);
		m_bGradientShadow = bGradient;
	} //End of SetTooltipShadow

	void CPPToolTip::SetImageShadow(int nOffsetX, int nOffsetY, BYTE nDarkenPercent /* = 50 */, 
		BOOL bGradient /* = TRUE */, int nDepthX /* = 7 */, int nDepthY /* = 7 */)
	{
		m_drawer.SetImageShadow(nOffsetX, nOffsetY, nDarkenPercent, bGradient, nDepthX, nDepthY);
	} //End of SetImageShadow

}